From 7811c9cfca123e84ab4fe8f5d3bdf09a0c412b1c Mon Sep 17 00:00:00 2001 From: Jerry Cao-CA Date: Mon, 29 Nov 2010 21:56:45 +0000 Subject: NTFS-3G initial import --- diff --git a/AUTHORS b/AUTHORS new file mode 100755 index 0000000..f9299b4 --- a/dev/null +++ b/AUTHORS @@ -0,0 +1,23 @@ + +Present authors of ntfs-3g in alphabetical order: + +Jean-Pierre Andre +Alon Bar-Lev +Martin Bene +Dominique L Bouix +Csaba Henk +Bernhard Kaindl +Erik Larsson +Alejandro Pulver +Szabolcs Szakacsits +Miklos Szeredi + + +Past authors in alphabetical order: + +Anton Altaparmakov +Mario Emmenlauer +Yuval Fledel +Yura Pakhuchiy +Richard Russon + diff --git a/Android.mk b/Android.mk new file mode 100755 index 0000000..b361890 --- a/dev/null +++ b/Android.mk @@ -0,0 +1,89 @@ +ifneq ($(TARGET_SIMULATOR), true) + +LOCAL_PATH := $(call my-dir) +MY_CFLAG:= -O2 -g -W -Wall -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H +################################################################### +## For stage1, we have to make libfuse +################################################################### +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := \ + libfuse-lite/fuse.c libfuse-lite/fusermount.c libfuse-lite/fuse_kern_chan.c libfuse-lite/fuse_loop.c\ + libfuse-lite/fuse_lowlevel.c libfuse-lite/fuse_opt.c libfuse-lite/fuse_session.c libfuse-lite/fuse_signals.c\ + libfuse-lite/helper.c libfuse-lite/mount.c libfuse-lite/mount_util.c + +LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/fuse-lite + +LOCAL_CFLAGS := $(MY_CFLAG) + +LOCAL_MODULE := libfuse +LOCAL_MODULE_TAGS := +LOCAL_SYSTEM_SHARED_LIBRARIES := libc libcutils + +include $(BUILD_STATIC_LIBRARY) + +################################################################### +## For stage2, we have to make libntfs-3g +################################################################### +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := libntfs-3g/acls.c libntfs-3g/attrib.c libntfs-3g/attrlist.c libntfs-3g/bitmap.c\ + libntfs-3g/bootsect.c libntfs-3g/cache.c libntfs-3g/collate.c libntfs-3g/compat.c libntfs-3g/compress.c \ + libntfs-3g/debug.c libntfs-3g/device.c libntfs-3g/dir.c libntfs-3g/efs.c libntfs-3g/index.c libntfs-3g/inode.c\ + libntfs-3g/lcnalloc.c libntfs-3g/logfile.c libntfs-3g/logging.c libntfs-3g/mft.c libntfs-3g/misc.c libntfs-3g/mst.c\ + libntfs-3g/object_id.c libntfs-3g/reparse.c libntfs-3g/runlist.c libntfs-3g/security.c libntfs-3g/unistr.c\ + libntfs-3g/unix_io.c libntfs-3g/volume.c + +LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/fuse-lite $(LOCAL_PATH)/include/ntfs-3g + +LOCAL_CFLAGS := $(MY_CFLAG) + +LOCAL_MODULE := libntfs-3g +LOCAL_MODULE_TAGS := +LOCAL_SYSTEM_SHARED_LIBRARIES := libc libcutils + +include $(BUILD_STATIC_LIBRARY) + + +################################################################### +## For stage3, we make ntfs-3g +################################################################### +include $(CLEAR_VARS) +LOCAL_SRC_FILES := src/ntfs-3g.c + +LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/fuse-lite $(LOCAL_PATH)/include/ntfs-3g \ + $(LOCAL_PATH)/src + +LOCAL_CFLAGS := $(MY_CFLAG) + +LOCAL_MODULE := ntfs-3g +LOCAL_MODULE_TAGS := +LOCAL_SYSTEM_SHARED_LIBRARIES := +LOCAL_STATIC_LIBRARIES := libfuse libntfs-3g libc libc_common + +include $(BUILD_EXECUTABLE) + + + +################################################################### +## +################################################################### +include $(CLEAR_VARS) +LOCAL_SRC_FILES := src/test.c + +LOCAL_C_INCLUDES := + +LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/fuse-lite $(LOCAL_PATH)/include/ntfs-3g \ + $(LOCAL_PATH)/src + +LOCAL_CFLAGS := $(MY_CFLAG) + +LOCAL_MODULE := ntfstest +LOCAL_MODULE_TAGS := +LOCAL_SYSTEM_SHARED_LIBRARIES := libc libcutils + + +include $(BUILD_EXECUTABLE) + + +endif diff --git a/Android.mk.bak b/Android.mk.bak new file mode 100755 index 0000000..2afb426 --- a/dev/null +++ b/Android.mk.bak @@ -0,0 +1,89 @@ +ifneq ($(TARGET_SIMULATOR), true) + +LOCAL_PATH := $(call my-dir) +MY_CFLAG:= -O2 -g -W -Wall -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_OFF_T_DEFINED_ -DHAVE_CONFIG_H +################################################################### +## For stage1, we have to make libfuse +################################################################### +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := \ + libfuse-lite/fuse.c libfuse-lite/fusermount.c libfuse-lite/fuse_kern_chan.c libfuse-lite/fuse_loop.c\ + libfuse-lite/fuse_lowlevel.c libfuse-lite/fuse_opt.c libfuse-lite/fuse_session.c libfuse-lite/fuse_signals.c\ + libfuse-lite/helper.c libfuse-lite/mount.c libfuse-lite/mount_util.c + +LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/fuse-lite + +LOCAL_CFLAGS := $(MY_CFLAG) + +LOCAL_MODULE := libfuse +LOCAL_MODULE_TAGS := +LOCAL_SYSTEM_SHARED_LIBRARIES := libc libcutils + +include $(BUILD_STATIC_LIBRARY) + +################################################################### +## For stage2, we have to make libntfs-3g +################################################################### +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := libntfs-3g/acls.c libntfs-3g/attrib.c libntfs-3g/attrlist.c libntfs-3g/bitmap.c\ + libntfs-3g/bootsect.c libntfs-3g/cache.c libntfs-3g/collate.c libntfs-3g/compat.c libntfs-3g/compress.c \ + libntfs-3g/debug.c libntfs-3g/device.c libntfs-3g/dir.c libntfs-3g/efs.c libntfs-3g/index.c libntfs-3g/inode.c\ + libntfs-3g/lcnalloc.c libntfs-3g/logfile.c libntfs-3g/logging.c libntfs-3g/mft.c libntfs-3g/misc.c libntfs-3g/mst.c\ + libntfs-3g/object_id.c libntfs-3g/reparse.c libntfs-3g/runlist.c libntfs-3g/security.c libntfs-3g/unistr.c\ + libntfs-3g/unix_io.c libntfs-3g/volume.c + +LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/fuse-lite $(LOCAL_PATH)/include/ntfs-3g + +LOCAL_CFLAGS := $(MY_CFLAG) + +LOCAL_MODULE := libntfs-3g +LOCAL_MODULE_TAGS := +LOCAL_SYSTEM_SHARED_LIBRARIES := libc libcutils + +include $(BUILD_STATIC_LIBRARY) + + +################################################################### +## For stage3, we make ntfs-3g +################################################################### +include $(CLEAR_VARS) +LOCAL_SRC_FILES := src/ntfs-3g.c + +LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/fuse-lite $(LOCAL_PATH)/include/ntfs-3g \ + $(LOCAL_PATH)/src + +LOCAL_CFLAGS := $(MY_CFLAG) + +LOCAL_MODULE := ntfs-3g +LOCAL_MODULE_TAGS := +LOCAL_SYSTEM_SHARED_LIBRARIES := +LOCAL_STATIC_LIBRARIES := libfuse libntfs-3g libc libc_common + +include $(BUILD_EXECUTABLE) + + + +################################################################### +## +################################################################### +include $(CLEAR_VARS) +LOCAL_SRC_FILES := src/test.c + +LOCAL_C_INCLUDES := + +LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/fuse-lite $(LOCAL_PATH)/include/ntfs-3g \ + $(LOCAL_PATH)/src + +LOCAL_CFLAGS := $(MY_CFLAG) + +LOCAL_MODULE := ntfstest +LOCAL_MODULE_TAGS := +LOCAL_SYSTEM_SHARED_LIBRARIES := libc libcutils + + +include $(BUILD_EXECUTABLE) + + +endif diff --git a/COPYING b/COPYING new file mode 100755 index 0000000..623b625 --- a/dev/null +++ b/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + 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 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/COPYING.LIB b/COPYING.LIB new file mode 100755 index 0000000..161a3d1 --- a/dev/null +++ b/COPYING.LIB @@ -0,0 +1,482 @@ + GNU LIBRARY GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1991 Free Software Foundation, Inc. + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the library GPL. It is + numbered 2 because it goes with version 2 of the ordinary GPL.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Library General Public License, applies to some +specially designated Free Software Foundation software, and to any +other libraries whose authors decide to use it. You can use it for +your libraries, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if +you distribute copies of the library, or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link a program with the library, you must provide +complete object files to the recipients so that they can relink them +with the library, after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + Our method of protecting your rights has two steps: (1) copyright +the library, and (2) offer you this license which gives you legal +permission to copy, distribute and/or modify the library. + + Also, for each distributor's protection, we want to make certain +that everyone understands that there is no warranty for this free +library. If the library is modified by someone else and passed on, we +want its recipients to know that what they have is not the original +version, so that any problems introduced by others will not reflect on +the original authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that companies distributing free +software will individually obtain patent licenses, thus in effect +transforming the program into proprietary software. To prevent this, +we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all. + + Most GNU software, including some libraries, is covered by the ordinary +GNU General Public License, which was designed for utility programs. This +license, the GNU Library General Public License, applies to certain +designated libraries. This license is quite different from the ordinary +one; be sure to read it in full, and don't assume that anything in it is +the same as in the ordinary license. + + The reason we have a separate public license for some libraries is that +they blur the distinction we usually make between modifying or adding to a +program and simply using it. Linking a program with a library, without +changing the library, is in some sense simply using the library, and is +analogous to running a utility program or application program. However, in +a textual and legal sense, the linked executable is a combined work, a +derivative of the original library, and the ordinary General Public License +treats it as such. + + Because of this blurred distinction, using the ordinary General +Public License for libraries did not effectively promote software +sharing, because most developers did not use the libraries. We +concluded that weaker conditions might promote sharing better. + + However, unrestricted linking of non-free programs would deprive the +users of those programs of all benefit from the free status of the +libraries themselves. This Library General Public License is intended to +permit developers of non-free programs to use free libraries, while +preserving your freedom as a user of such programs to change the free +libraries that are incorporated in them. (We have not seen how to achieve +this as regards changes in header files, but we have achieved it as regards +changes in the actual functions of the Library.) The hope is that this +will lead to faster development of free libraries. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, while the latter only +works together with the library. + + Note that it is possible for a library to be covered by the ordinary +General Public License rather than by this special one. + + GNU LIBRARY GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library which +contains a notice placed by the copyright holder or other authorized +party saying it may be distributed under the terms of this Library +General Public License (also called "this License"). Each licensee is +addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also compile or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + c) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + d) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the source code distributed need not include anything that is normally +distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Library 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 Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "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 +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY 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 +LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + MA 02111-1307, USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/CREDITS b/CREDITS new file mode 100755 index 0000000..844a147 --- a/dev/null +++ b/CREDITS @@ -0,0 +1,41 @@ +The following people have contributed directly or indirectly +to the ntfs-3g project. + +Please let ntfs-3g-devel@lists.sf.net know if you believe +someone is missing, or if you prefer not to be listed. + +Dominique L Bouix +Csaba Henk +Max Khon +Auri Hautamäki +Gergely Erdelyi +Anton Altaparmakov +Peter Boross +Don Bright +Mario Emmenlauer +Yuval Fledel +Kano from Kanotix +Roland Kletzing +Maarten Lankhorst +Gergely Madarasz +Patrick McLean +Florent Mertens +Yura Pakhuchiy +Miklos Szeredi +Bartosz Taudul +Zhanglinbao +Wade Fitzpatrick +Carsten Einig +Adam Cecile +Bruno Damour +Ales Fruman +Curt McDowell +Thomas Franken +Jonatan Lambert +Klaus Knopper +Zhanglinbao +Ismail Donmez +Laszlo Dvornik +Pallaghy Ajtony +Szabolcs Szakacsits + diff --git a/ChangeLog b/ChangeLog new file mode 100755 index 0000000..5021888 --- a/dev/null +++ b/ChangeLog @@ -0,0 +1,7 @@ + +Detailed ChangeLog can be found at http://mercurial.creo.hu/repos/ntfs-3g-hg/ + +Alternatively it can be generated from the CVS source repository by cvs2cl.pl. +Instructions for CVS access: http://sourceforge.net/cvs/?group_id=181143 +Home of the cvs2cl.pl utility: http://www.red-bean.com/cvs2cl/ + diff --git a/INSTALL b/INSTALL new file mode 100755 index 0000000..d3c5b40 --- a/dev/null +++ b/INSTALL @@ -0,0 +1,237 @@ +Installation Instructions +************************* + +Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005, +2006, 2007 Free Software Foundation, Inc. + +This file is free documentation; the Free Software Foundation gives +unlimited permission to copy, distribute and modify it. + +Basic Installation +================== + +Briefly, the shell commands `./configure; make; make install' should +configure, build, and install this package. The following +more-detailed instructions are generic; see the `README' file for +instructions specific to this package. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, and a +file `config.log' containing compiler output (useful mainly for +debugging `configure'). + + It can also use an optional file (typically called `config.cache' +and enabled with `--cache-file=config.cache' or simply `-C') that saves +the results of its tests to speed up reconfiguring. Caching is +disabled by default to prevent problems with accidental use of stale +cache files. + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If you are using the cache, and at +some point `config.cache' contains results you don't want to keep, you +may remove or edit it. + + The file `configure.ac' (or `configure.in') is used to create +`configure' by a program called `autoconf'. You need `configure.ac' if +you want to change it or regenerate `configure' using a newer version +of `autoconf'. + +The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. + + Running `configure' might take a while. While running, it prints + some messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package. + + 4. Type `make install' to install the programs and any data files and + documentation. + + 5. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + + 6. Often, you can also type `make uninstall' to remove the installed + files again. + +Compilers and Options +===================== + +Some systems require unusual options for compilation or linking that the +`configure' script does not know about. Run `./configure --help' for +details on some of the pertinent environment variables. + + You can give `configure' initial values for configuration parameters +by setting variables in the command line or in the environment. Here +is an example: + + ./configure CC=c99 CFLAGS=-g LIBS=-lposix + + *Note Defining Variables::, for more details. + +Compiling For Multiple Architectures +==================================== + +You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you can use GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. + + With a non-GNU `make', it is safer to compile the package for one +architecture at a time in the source code directory. After you have +installed the package for one architecture, use `make distclean' before +reconfiguring for another architecture. + +Installation Names +================== + +By default, `make install' installs the package's commands under +`/usr/local/bin', include files under `/usr/local/include', etc. You +can specify an installation prefix other than `/usr/local' by giving +`configure' the option `--prefix=PREFIX'. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +pass the option `--exec-prefix=PREFIX' to `configure', the package uses +PREFIX as the prefix for installing programs and libraries. +Documentation and other data files still use the regular prefix. + + In addition, if you use an unusual directory layout you can give +options like `--bindir=DIR' to specify different values for particular +kinds of files. Run `configure --help' for a list of the directories +you can set and what kinds of files go in them. + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + +Optional Features +================= + +Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + +Specifying the System Type +========================== + +There may be some features `configure' cannot figure out automatically, +but needs to determine by the type of machine the package will run on. +Usually, assuming the package is built to be run on the _same_ +architectures, `configure' can figure that out, but if it prints a +message saying it cannot guess the machine type, give it the +`--build=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name which has the form: + + CPU-COMPANY-SYSTEM + +where SYSTEM can have one of these forms: + + OS KERNEL-OS + + See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the machine type. + + If you are _building_ compiler tools for cross-compiling, you should +use the option `--target=TYPE' to select the type of system they will +produce code for. + + If you want to _use_ a cross compiler, that generates code for a +platform different from the build platform, you should specify the +"host" platform (i.e., that on which the generated programs will +eventually be run) with `--host=TYPE'. + +Sharing Defaults +================ + +If you want to set default values for `configure' scripts to share, you +can create a site shell script called `config.site' that gives default +values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Defining Variables +================== + +Variables not defined in a site shell script can be set in the +environment passed to `configure'. However, some packages may run +configure again during the build, and the customized values of these +variables may be lost. In order to avoid this problem, you should set +them in the `configure' command line, using `VAR=value'. For example: + + ./configure CC=/usr/local2/bin/gcc + +causes the specified `gcc' to be used as the C compiler (unless it is +overridden in the site shell script). + +Unfortunately, this technique does not work for `CONFIG_SHELL' due to +an Autoconf bug. Until the bug is fixed you can use this workaround: + + CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash + +`configure' Invocation +====================== + +`configure' recognizes the following options to control how it operates. + +`--help' +`-h' + Print a summary of the options to `configure', and exit. + +`--version' +`-V' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`--cache-file=FILE' + Enable the cache: use and save the results of the tests in FILE, + traditionally `config.cache'. FILE defaults to `/dev/null' to + disable caching. + +`--config-cache' +`-C' + Alias for `--cache-file=config.cache'. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. To + suppress all normal output, redirect it to `/dev/null' (any error + messages will still be shown). + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`configure' also accepts some other, not widely useful, options. Run +`configure --help' for more details. + diff --git a/Makefile b/Makefile new file mode 100755 index 0000000..c3adcc8 --- a/dev/null +++ b/Makefile @@ -0,0 +1,715 @@ +# Makefile.in generated by automake 1.10.1 from Makefile.am. +# Makefile. Generated from Makefile.in by configure. + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008 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. + + + + +pkgdatadir = $(datadir)/ntfs-3g +pkglibdir = $(libdir)/ntfs-3g +pkgincludedir = $(includedir)/ntfs-3g +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 = : +build_triplet = i686-pc-linux-gnu +host_triplet = arc-unknown-linux-uclibc +target_triplet = arc-unknown-linux-uclibc +subdir = . +DIST_COMMON = README $(am__configure_deps) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in $(srcdir)/config.h.in \ + $(top_srcdir)/configure AUTHORS COPYING COPYING.LIB ChangeLog \ + INSTALL NEWS compile config.guess config.sub depcomp \ + install-sh ltmain.sh missing +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ + configure.lineno config.status.lineno +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = config.h +CONFIG_CLEAN_FILES = +SOURCES = +DIST_SOURCES = +RECURSIVE_TARGETS = all-recursive check-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 uninstall-recursive +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 = `echo $$p | sed -e 's|^.*/||'`; +am__installdirs = "$(DESTDIR)$(docdir)" +docDATA_INSTALL = $(INSTALL_DATA) +DATA = $(doc_DATA) +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = $(SUBDIRS) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +distdir = $(PACKAGE)-$(VERSION) +top_distdir = $(distdir) +am__remove_distdir = \ + { test ! -d $(distdir) \ + || { find $(distdir) -type d ! -perm -200 -exec chmod u+w {} ';' \ + && rm -fr $(distdir); }; } +DIST_ARCHIVES = $(distdir).tar.gz +GZIP_ENV = --best +distuninstallcheck_listfiles = find . -type f -print +distcleancheck_listfiles = find . -type f -print +ACLOCAL = ${SHELL} /mnt/fileroot/michael.wang/linux-top-pub/ui_ref/trunk/build/packages/ntfs-3g-2010.5.16/missing --run aclocal-1.10 +AMTAR = ${SHELL} /mnt/fileroot/michael.wang/linux-top-pub/ui_ref/trunk/build/packages/ntfs-3g-2010.5.16/missing --run tar +AR = arc-linux-uclibc-ar +AUTOCONF = ${SHELL} /mnt/fileroot/michael.wang/linux-top-pub/ui_ref/trunk/build/packages/ntfs-3g-2010.5.16/missing --run autoconf +AUTOHEADER = ${SHELL} /mnt/fileroot/michael.wang/linux-top-pub/ui_ref/trunk/build/packages/ntfs-3g-2010.5.16/missing --run autoheader +AUTOMAKE = ${SHELL} /mnt/fileroot/michael.wang/linux-top-pub/ui_ref/trunk/build/packages/ntfs-3g-2010.5.16/missing --run automake-1.10 +AWK = mawk +CC = arc-linux-uclibc-gcc +CCDEPMODE = depmode=gcc3 +CFLAGS = -mA7 -g -Wall +CPP = arc-linux-uclibc-gcc -E +CPPFLAGS = +CXX = arc-linux-uclibc-g++ +CXXCPP = arc-linux-uclibc-g++ -E +CXXDEPMODE = depmode=gcc3 +CXXFLAGS = -g -O2 +CYGPATH_W = echo +DEFS = -DHAVE_CONFIG_H +DEPDIR = .deps +DSYMUTIL = +ECHO = echo +ECHO_C = +ECHO_N = -n +ECHO_T = +EGREP = /bin/grep -E +EXEEXT = +F77 = +FFLAGS = +FUSE_MODULE_CFLAGS = +FUSE_MODULE_LIBS = +GREP = /bin/grep +INSTALL = /usr/bin/install -c +INSTALL_DATA = ${INSTALL} -m 644 +INSTALL_PROGRAM = ${INSTALL} +INSTALL_SCRIPT = ${INSTALL} +INSTALL_STRIP_PROGRAM = $(install_sh) -c -s +LDCONFIG = /sbin/ldconfig +LDFLAGS = +LIBFUSE_LITE_LIBS = -lpthread +LIBNTFS_3G_VERSION = 76 +LIBOBJS = ${LIBOBJDIR}memcmp$U.o ${LIBOBJDIR}lstat$U.o ${LIBOBJDIR}stat$U.o +LIBS = +LIBTOOL = $(SHELL) $(top_builddir)/libtool +LN_S = ln -s +LTLIBOBJS = ${LIBOBJDIR}memcmp$U.lo ${LIBOBJDIR}lstat$U.lo ${LIBOBJDIR}stat$U.lo +MAINT = # +MAKEINFO = ${SHELL} /mnt/fileroot/michael.wang/linux-top-pub/ui_ref/trunk/build/packages/ntfs-3g-2010.5.16/missing --run makeinfo +MKDIR_P = /bin/mkdir -p +MV = /bin/mv +NMEDIT = +OBJEXT = o +OUTPUT_FORMAT = +PACKAGE = ntfs-3g +PACKAGE_BUGREPORT = ntfs-3g-devel@lists.sf.net +PACKAGE_NAME = ntfs-3g +PACKAGE_STRING = ntfs-3g 2010.5.16 +PACKAGE_TARNAME = ntfs-3g +PACKAGE_VERSION = 2010.5.16 +PATH_SEPARATOR = : +PKG_CONFIG = +RANLIB = arc-linux-uclibc-ranlib +RM = /bin/rm +SED = /bin/sed +SET_MAKE = +SHELL = /bin/bash +STRIP = arc-linux-uclibc-strip +VERSION = 2010.5.16 +abs_builddir = /mnt/fileroot/michael.wang/linux-top-pub/ui_ref/trunk/build/packages/ntfs-3g-2010.5.16 +abs_srcdir = /mnt/fileroot/michael.wang/linux-top-pub/ui_ref/trunk/build/packages/ntfs-3g-2010.5.16 +abs_top_builddir = /mnt/fileroot/michael.wang/linux-top-pub/ui_ref/trunk/build/packages/ntfs-3g-2010.5.16 +abs_top_srcdir = /mnt/fileroot/michael.wang/linux-top-pub/ui_ref/trunk/build/packages/ntfs-3g-2010.5.16 +ac_ct_CC = +ac_ct_CXX = +ac_ct_F77 = +am__include = include +am__leading_dot = . +am__quote = +am__tar = ${AMTAR} chof - "$$tardir" +am__untar = ${AMTAR} xf - +bindir = ${exec_prefix}/bin +build = i686-pc-linux-gnu +build_alias = +build_cpu = i686 +build_os = linux-gnu +build_vendor = pc +builddir = . +datadir = ${datarootdir} +datarootdir = ${prefix}/share +docdir = ${datarootdir}/doc/${PACKAGE_TARNAME} +dvidir = ${docdir} +exec_prefix = /mnt/fileroot/michael.wang/linux-top-pub/ui_ref/trunk/bld_7266_h_64x2/./rootfs +host = arc-unknown-linux-uclibc +host_alias = arc-linux-uclibc +host_cpu = arc +host_os = linux-uclibc +host_vendor = unknown +htmldir = ${docdir} +includedir = ${prefix}/include +infodir = ${datarootdir}/info +install_sh = $(SHELL) /mnt/fileroot/michael.wang/linux-top-pub/ui_ref/trunk/build/packages/ntfs-3g-2010.5.16/install-sh +libdir = ${exec_prefix}/lib +libexecdir = ${exec_prefix}/libexec +localedir = ${datarootdir}/locale +localstatedir = ${prefix}/var +mandir = ${datarootdir}/man +mkdir_p = /bin/mkdir -p +ntfs3gincludedir = $(includedir)/ntfs-3g +oldincludedir = /usr/include +pdfdir = ${docdir} +pkgconfigdir = $(libdir)/pkgconfig +prefix = /mnt/fileroot/michael.wang/linux-top-pub/ui_ref/trunk/bld_7266_h_64x2/./rootfs +program_transform_name = s,x,x, +psdir = ${docdir} +rootbindir = $(bindir) +rootlibdir = $(libdir) +rootsbindir = $(sbindir) +sbindir = ${exec_prefix}/sbin +sharedstatedir = ${prefix}/com +srcdir = . +sysconfdir = ${prefix}/etc +target = arc-unknown-linux-uclibc +target_alias = +target_cpu = arc +target_os = linux-uclibc +target_vendor = unknown +top_builddir = . +top_srcdir = . +AUTOMAKE_OPTIONS = gnu +ACLOCAL_AMFLAGS = -I m4 +EXTRA_DIST = AUTHORS CREDITS COPYING NEWS autogen.sh +MAINTAINERCLEANFILES = \ + $(srcdir)/configure \ + $(srcdir)/Makefile.in \ + $(srcdir)/aclocal.m4 \ + $(srcdir)/compile \ + $(srcdir)/depcomp \ + $(srcdir)/install-sh \ + $(srcdir)/ltmain.sh \ + $(srcdir)/missing \ + $(srcdir)/config.guess \ + $(srcdir)/config.sub \ + $(srcdir)/config.h.in \ + $(srcdir)/config.h.in~ \ + $(srcdir)/INSTALL \ + $(srcdir)/m4/ltsugar.m4 \ + $(srcdir)/m4/libtool.m4 \ + $(srcdir)/m4/ltversion.m4 \ + $(srcdir)/m4/lt~obsolete.m4 \ + $(srcdir)/m4/ltoptions.m4 + +SUBDIRS = include libfuse-lite libntfs-3g src +doc_DATA = README +all: config.h + $(MAKE) $(AM_MAKEFLAGS) all-recursive + +.SUFFIXES: +am--refresh: + @: +$(srcdir)/Makefile.in: # $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + echo ' cd $(srcdir) && $(AUTOMAKE) --gnu '; \ + cd $(srcdir) && $(AUTOMAKE) --gnu \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu Makefile +.PRECIOUS: 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__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + $(SHELL) ./config.status --recheck + +$(top_srcdir)/configure: # $(am__configure_deps) + cd $(srcdir) && $(AUTOCONF) +$(ACLOCAL_M4): # $(am__aclocal_m4_deps) + cd $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) + +config.h: stamp-h1 + @if test ! -f $@; then \ + rm -f stamp-h1; \ + $(MAKE) $(AM_MAKEFLAGS) stamp-h1; \ + else :; fi + +stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status + @rm -f stamp-h1 + cd $(top_builddir) && $(SHELL) ./config.status config.h +$(srcdir)/config.h.in: # $(am__configure_deps) + cd $(top_srcdir) && $(AUTOHEADER) + rm -f stamp-h1 + touch $@ + +distclean-hdr: + -rm -f config.h stamp-h1 + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + -rm -f libtool +install-docDATA: $(doc_DATA) + @$(NORMAL_INSTALL) + test -z "$(docdir)" || $(MKDIR_P) "$(DESTDIR)$(docdir)" + @list='$(doc_DATA)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f=$(am__strip_dir) \ + echo " $(docDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(docdir)/$$f'"; \ + $(docDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(docdir)/$$f"; \ + done + +uninstall-docDATA: + @$(NORMAL_UNINSTALL) + @list='$(doc_DATA)'; for p in $$list; do \ + f=$(am__strip_dir) \ + echo " rm -f '$(DESTDIR)$(docdir)/$$f'"; \ + rm -f "$(DESTDIR)$(docdir)/$$f"; \ + done + +# 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. +$(RECURSIVE_TARGETS): + @failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; 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; \ + (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" + +$(RECURSIVE_CLEAN_TARGETS): + @failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: tags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + 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 || \ + tags="$$tags $$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: ctags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(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 $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$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 \ + test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + distdir=`$(am__cd) $(distdir) && pwd`; \ + top_distdir=`$(am__cd) $(top_distdir) && pwd`; \ + (cd $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$top_distdir" \ + distdir="$$distdir/$$subdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + distdir) \ + || exit 1; \ + fi; \ + done + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$(top_distdir)" distdir="$(distdir)" \ + dist-hook + -find $(distdir) -type d ! -perm -777 -exec chmod a+rwx {} \; -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) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz + $(am__remove_distdir) + +dist-bzip2: distdir + tardir=$(distdir) && $(am__tar) | bzip2 -9 -c >$(distdir).tar.bz2 + $(am__remove_distdir) + +dist-lzma: distdir + tardir=$(distdir) && $(am__tar) | lzma -9 -c >$(distdir).tar.lzma + $(am__remove_distdir) + +dist-tarZ: distdir + tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z + $(am__remove_distdir) + +dist-shar: distdir + shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz + $(am__remove_distdir) + +dist-zip: distdir + -rm -f $(distdir).zip + zip -rq $(distdir).zip $(distdir) + $(am__remove_distdir) + +dist dist-all: distdir + tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz + $(am__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*) \ + GZIP=$(GZIP_ENV) gunzip -c $(distdir).tar.gz | $(am__untar) ;;\ + *.tar.bz2*) \ + bunzip2 -c $(distdir).tar.bz2 | $(am__untar) ;;\ + *.tar.lzma*) \ + unlzma -c $(distdir).tar.lzma | $(am__untar) ;;\ + *.tar.Z*) \ + uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ + *.shar.gz*) \ + GZIP=$(GZIP_ENV) gunzip -c $(distdir).shar.gz | unshar ;;\ + *.zip*) \ + unzip $(distdir).zip ;;\ + esac + chmod -R a-w $(distdir); chmod a+w $(distdir) + mkdir $(distdir)/_build + mkdir $(distdir)/_inst + chmod a-w $(distdir) + dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ + && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ + && cd $(distdir)/_build \ + && ../configure --srcdir=.. --prefix="$$dc_install_base" \ + $(DISTCHECK_CONFIGURE_FLAGS) \ + && $(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 + $(am__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: + @cd $(distuninstallcheck_dir) \ + && test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \ + || { 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 $(DATA) config.h +installdirs: installdirs-recursive +installdirs-am: + for dir in "$(DESTDIR)$(docdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +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: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) +clean: clean-recursive + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-recursive + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-hdr \ + distclean-libtool distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +info: info-recursive + +info-am: + +install-data-am: install-docDATA + +install-dvi: install-dvi-recursive + +install-exec-am: + +install-html: install-html-recursive + +install-info: install-info-recursive + +install-man: + +install-pdf: install-pdf-recursive + +install-ps: install-ps-recursive + +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 mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: uninstall-docDATA + +.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) install-am \ + install-strip + +.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ + all all-am am--refresh check check-am clean clean-generic \ + clean-libtool ctags ctags-recursive dist dist-all dist-bzip2 \ + dist-gzip dist-hook dist-lzma dist-shar dist-tarZ dist-zip \ + distcheck distclean distclean-generic distclean-hdr \ + distclean-libtool distclean-tags distcleancheck distdir \ + distuninstallcheck dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am \ + install-docDATA 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 \ + mostlyclean-libtool pdf pdf-am ps ps-am tags tags-recursive \ + uninstall uninstall-am uninstall-docDATA + + +dist-hook: + $(MKDIR_P) "$(distdir)/m4" +# 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: diff --git a/Makefile.am b/Makefile.am new file mode 100755 index 0000000..7d883a4 --- a/dev/null +++ b/Makefile.am @@ -0,0 +1,66 @@ + +MAINTAINERCLEANFILES = $(srcdir)/Makefile.in + +if FUSE_INTERNAL +FUSE_CFLAGS = -I$(top_srcdir)/include/fuse-lite +FUSE_LIBS = +else +FUSE_CFLAGS = $(FUSE_MODULE_CFLAGS) +FUSE_LIBS = $(FUSE_MODULE_LIBS) +endif + +bin_PROGRAMS = ntfs-3g.probe +rootbin_PROGRAMS = ntfs-3g lowntfs-3g +rootsbin_DATA = #Create directory +man_MANS = ntfs-3g.8 ntfs-3g.probe.8 + +ntfs_3g_LDADD = $(FUSE_LIBS) $(top_builddir)/libntfs-3g/libntfs-3g.la +if REALLYSTATIC +ntfs_3g_LDFLAGS = $(AM_LDFLAGS) -all-static +endif +ntfs_3g_CFLAGS = \ + $(AM_CFLAGS) \ + -DFUSE_USE_VERSION=26 \ + $(FUSE_CFLAGS) \ + -I$(top_srcdir)/include/ntfs-3g +ntfs_3g_SOURCES = ntfs-3g.c + +lowntfs_3g_LDADD = $(FUSE_LIBS) $(top_builddir)/libntfs-3g/libntfs-3g.la +if REALLYSTATIC +lowntfs_3g_LDFLAGS = $(AM_LDFLAGS) -all-static +endif +lowntfs_3g_CFLAGS = \ + $(AM_CFLAGS) \ + -DFUSE_USE_VERSION=26 \ + $(FUSE_CFLAGS) \ + -I$(top_srcdir)/include/ntfs-3g +lowntfs_3g_SOURCES = lowntfs-3g.c + +ntfs_3g_probe_LDADD = $(top_builddir)/libntfs-3g/libntfs-3g.la +if REALLYSTATIC +ntfs_3g_probe_LDFLAGS = $(AM_LDFLAGS) -all-static +endif +ntfs_3g_probe_CFLAGS = $(AM_CFLAGS) -I$(top_srcdir)/include/ntfs-3g +ntfs_3g_probe_SOURCES = ntfs-3g.probe.c + +if RUN_LDCONFIG +install-exec-hook: + $(LDCONFIG) +endif + +if ENABLE_MOUNT_HELPER +install-exec-local: install-rootbinPROGRAMS + $(MKDIR_P) "$(DESTDIR)/sbin" + $(LN_S) -f "$(rootbindir)/ntfs-3g" "$(DESTDIR)/sbin/mount.ntfs-3g" + $(LN_S) -f "$(rootbindir)/lowntfs-3g" "$(DESTDIR)/sbin/mount.lowntfs-3g" +endif + +install-data-local: install-man8 + $(LN_S) -f ntfs-3g.8 "$(DESTDIR)$(man8dir)/mount.ntfs-3g.8" + $(LN_S) -f ntfs-3g.8 "$(DESTDIR)$(man8dir)/mount.lowntfs-3g.8" + +uninstall-local: + $(RM) -f "$(DESTDIR)$(man8dir)/mount.ntfs-3g.8" +if ENABLE_MOUNT_HELPER + $(RM) -f "$(DESTDIR)/sbin/mount.ntfs-3g" "$(DESTDIR)/sbin/mount.lowntfs-3g" +endif diff --git a/Makefile.in b/Makefile.in new file mode 100755 index 0000000..4fc593f --- a/dev/null +++ b/Makefile.in @@ -0,0 +1,722 @@ +# Makefile.in generated by automake 1.10.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008 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@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@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 = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +bin_PROGRAMS = ntfs-3g.probe$(EXEEXT) +rootbin_PROGRAMS = ntfs-3g$(EXEEXT) lowntfs-3g$(EXEEXT) +subdir = src +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ + $(srcdir)/ntfs-3g.8.in $(srcdir)/ntfs-3g.probe.8.in \ + $(srcdir)/ntfs-3g.secaudit.8.in $(srcdir)/ntfs-3g.usermap.8.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = ntfs-3g.8 ntfs-3g.probe.8 ntfs-3g.usermap.8 \ + ntfs-3g.secaudit.8 +am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(rootbindir)" \ + "$(DESTDIR)$(man8dir)" "$(DESTDIR)$(rootsbindir)" +binPROGRAMS_INSTALL = $(INSTALL_PROGRAM) +rootbinPROGRAMS_INSTALL = $(INSTALL_PROGRAM) +PROGRAMS = $(bin_PROGRAMS) $(rootbin_PROGRAMS) +am_lowntfs_3g_OBJECTS = lowntfs_3g-lowntfs-3g.$(OBJEXT) +lowntfs_3g_OBJECTS = $(am_lowntfs_3g_OBJECTS) +am__DEPENDENCIES_1 = +@FUSE_INTERNAL_FALSE@am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1) +lowntfs_3g_DEPENDENCIES = $(am__DEPENDENCIES_2) \ + $(top_builddir)/libntfs-3g/libntfs-3g.la +lowntfs_3g_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(lowntfs_3g_CFLAGS) \ + $(CFLAGS) $(lowntfs_3g_LDFLAGS) $(LDFLAGS) -o $@ +am_ntfs_3g_OBJECTS = ntfs_3g-ntfs-3g.$(OBJEXT) +ntfs_3g_OBJECTS = $(am_ntfs_3g_OBJECTS) +ntfs_3g_DEPENDENCIES = $(am__DEPENDENCIES_2) \ + $(top_builddir)/libntfs-3g/libntfs-3g.la +ntfs_3g_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(ntfs_3g_CFLAGS) $(CFLAGS) \ + $(ntfs_3g_LDFLAGS) $(LDFLAGS) -o $@ +am_ntfs_3g_probe_OBJECTS = ntfs_3g_probe-ntfs-3g.probe.$(OBJEXT) +ntfs_3g_probe_OBJECTS = $(am_ntfs_3g_probe_OBJECTS) +ntfs_3g_probe_DEPENDENCIES = $(top_builddir)/libntfs-3g/libntfs-3g.la +ntfs_3g_probe_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(ntfs_3g_probe_CFLAGS) \ + $(CFLAGS) $(ntfs_3g_probe_LDFLAGS) $(LDFLAGS) -o $@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(lowntfs_3g_SOURCES) $(ntfs_3g_SOURCES) \ + $(ntfs_3g_probe_SOURCES) +DIST_SOURCES = $(lowntfs_3g_SOURCES) $(ntfs_3g_SOURCES) \ + $(ntfs_3g_probe_SOURCES) +man8dir = $(mandir)/man8 +NROFF = nroff +MANS = $(man_MANS) +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 = `echo $$p | sed -e 's|^.*/||'`; +rootsbinDATA_INSTALL = $(INSTALL_DATA) +DATA = $(rootsbin_DATA) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DSYMUTIL = @DSYMUTIL@ +ECHO = @ECHO@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +F77 = @F77@ +FFLAGS = @FFLAGS@ +FUSE_MODULE_CFLAGS = @FUSE_MODULE_CFLAGS@ +FUSE_MODULE_LIBS = @FUSE_MODULE_LIBS@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDCONFIG = @LDCONFIG@ +LDFLAGS = @LDFLAGS@ +LIBFUSE_LITE_LIBS = @LIBFUSE_LITE_LIBS@ +LIBNTFS_3G_VERSION = @LIBNTFS_3G_VERSION@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MV = @MV@ +NMEDIT = @NMEDIT@ +OBJEXT = @OBJEXT@ +OUTPUT_FORMAT = @OUTPUT_FORMAT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PKG_CONFIG = @PKG_CONFIG@ +RANLIB = @RANLIB@ +RM = @RM@ +SED = @SED@ +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_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_F77 = @ac_ct_F77@ +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 = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +ntfs3gincludedir = @ntfs3gincludedir@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgconfigdir = @pkgconfigdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +rootbindir = @rootbindir@ +rootlibdir = @rootlibdir@ +rootsbindir = @rootsbindir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +MAINTAINERCLEANFILES = $(srcdir)/Makefile.in +@FUSE_INTERNAL_FALSE@FUSE_CFLAGS = $(FUSE_MODULE_CFLAGS) +@FUSE_INTERNAL_TRUE@FUSE_CFLAGS = -I$(top_srcdir)/include/fuse-lite +@FUSE_INTERNAL_FALSE@FUSE_LIBS = $(FUSE_MODULE_LIBS) +@FUSE_INTERNAL_TRUE@FUSE_LIBS = +rootsbin_DATA = #Create directory +man_MANS = ntfs-3g.8 ntfs-3g.probe.8 +ntfs_3g_LDADD = $(FUSE_LIBS) $(top_builddir)/libntfs-3g/libntfs-3g.la +@REALLYSTATIC_TRUE@ntfs_3g_LDFLAGS = $(AM_LDFLAGS) -all-static +ntfs_3g_CFLAGS = \ + $(AM_CFLAGS) \ + -DFUSE_USE_VERSION=26 \ + $(FUSE_CFLAGS) \ + -I$(top_srcdir)/include/ntfs-3g + +ntfs_3g_SOURCES = ntfs-3g.c +lowntfs_3g_LDADD = $(FUSE_LIBS) $(top_builddir)/libntfs-3g/libntfs-3g.la +@REALLYSTATIC_TRUE@lowntfs_3g_LDFLAGS = $(AM_LDFLAGS) -all-static +lowntfs_3g_CFLAGS = \ + $(AM_CFLAGS) \ + -DFUSE_USE_VERSION=26 \ + $(FUSE_CFLAGS) \ + -I$(top_srcdir)/include/ntfs-3g + +lowntfs_3g_SOURCES = lowntfs-3g.c +ntfs_3g_probe_LDADD = $(top_builddir)/libntfs-3g/libntfs-3g.la +@REALLYSTATIC_TRUE@ntfs_3g_probe_LDFLAGS = $(AM_LDFLAGS) -all-static +ntfs_3g_probe_CFLAGS = $(AM_CFLAGS) -I$(top_srcdir)/include/ntfs-3g +ntfs_3g_probe_SOURCES = ntfs-3g.probe.c +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/Makefile +.PRECIOUS: 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__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +ntfs-3g.8: $(top_builddir)/config.status $(srcdir)/ntfs-3g.8.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +ntfs-3g.probe.8: $(top_builddir)/config.status $(srcdir)/ntfs-3g.probe.8.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +ntfs-3g.usermap.8: $(top_builddir)/config.status $(srcdir)/ntfs-3g.usermap.8.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +ntfs-3g.secaudit.8: $(top_builddir)/config.status $(srcdir)/ntfs-3g.secaudit.8.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ + if test -f $$p \ + || test -f $$p1 \ + ; then \ + f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(binPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(bindir)/$$f'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(binPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(bindir)/$$f" || exit 1; \ + else :; fi; \ + done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " rm -f '$(DESTDIR)$(bindir)/$$f'"; \ + rm -f "$(DESTDIR)$(bindir)/$$f"; \ + done + +clean-binPROGRAMS: + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f $$p $$f"; \ + rm -f $$p $$f ; \ + done +install-rootbinPROGRAMS: $(rootbin_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(rootbindir)" || $(MKDIR_P) "$(DESTDIR)$(rootbindir)" + @list='$(rootbin_PROGRAMS)'; for p in $$list; do \ + p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ + if test -f $$p \ + || test -f $$p1 \ + ; then \ + f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(rootbinPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(rootbindir)/$$f'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(rootbinPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(rootbindir)/$$f" || exit 1; \ + else :; fi; \ + done + +uninstall-rootbinPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(rootbin_PROGRAMS)'; for p in $$list; do \ + f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " rm -f '$(DESTDIR)$(rootbindir)/$$f'"; \ + rm -f "$(DESTDIR)$(rootbindir)/$$f"; \ + done + +clean-rootbinPROGRAMS: + @list='$(rootbin_PROGRAMS)'; for p in $$list; do \ + f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f $$p $$f"; \ + rm -f $$p $$f ; \ + done +lowntfs-3g$(EXEEXT): $(lowntfs_3g_OBJECTS) $(lowntfs_3g_DEPENDENCIES) + @rm -f lowntfs-3g$(EXEEXT) + $(lowntfs_3g_LINK) $(lowntfs_3g_OBJECTS) $(lowntfs_3g_LDADD) $(LIBS) +ntfs-3g$(EXEEXT): $(ntfs_3g_OBJECTS) $(ntfs_3g_DEPENDENCIES) + @rm -f ntfs-3g$(EXEEXT) + $(ntfs_3g_LINK) $(ntfs_3g_OBJECTS) $(ntfs_3g_LDADD) $(LIBS) +ntfs-3g.probe$(EXEEXT): $(ntfs_3g_probe_OBJECTS) $(ntfs_3g_probe_DEPENDENCIES) + @rm -f ntfs-3g.probe$(EXEEXT) + $(ntfs_3g_probe_LINK) $(ntfs_3g_probe_OBJECTS) $(ntfs_3g_probe_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lowntfs_3g-lowntfs-3g.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntfs_3g-ntfs-3g.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntfs_3g_probe-ntfs-3g.probe.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +lowntfs_3g-lowntfs-3g.o: lowntfs-3g.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lowntfs_3g_CFLAGS) $(CFLAGS) -MT lowntfs_3g-lowntfs-3g.o -MD -MP -MF $(DEPDIR)/lowntfs_3g-lowntfs-3g.Tpo -c -o lowntfs_3g-lowntfs-3g.o `test -f 'lowntfs-3g.c' || echo '$(srcdir)/'`lowntfs-3g.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/lowntfs_3g-lowntfs-3g.Tpo $(DEPDIR)/lowntfs_3g-lowntfs-3g.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='lowntfs-3g.c' object='lowntfs_3g-lowntfs-3g.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lowntfs_3g_CFLAGS) $(CFLAGS) -c -o lowntfs_3g-lowntfs-3g.o `test -f 'lowntfs-3g.c' || echo '$(srcdir)/'`lowntfs-3g.c + +lowntfs_3g-lowntfs-3g.obj: lowntfs-3g.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lowntfs_3g_CFLAGS) $(CFLAGS) -MT lowntfs_3g-lowntfs-3g.obj -MD -MP -MF $(DEPDIR)/lowntfs_3g-lowntfs-3g.Tpo -c -o lowntfs_3g-lowntfs-3g.obj `if test -f 'lowntfs-3g.c'; then $(CYGPATH_W) 'lowntfs-3g.c'; else $(CYGPATH_W) '$(srcdir)/lowntfs-3g.c'; fi` +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/lowntfs_3g-lowntfs-3g.Tpo $(DEPDIR)/lowntfs_3g-lowntfs-3g.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='lowntfs-3g.c' object='lowntfs_3g-lowntfs-3g.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lowntfs_3g_CFLAGS) $(CFLAGS) -c -o lowntfs_3g-lowntfs-3g.obj `if test -f 'lowntfs-3g.c'; then $(CYGPATH_W) 'lowntfs-3g.c'; else $(CYGPATH_W) '$(srcdir)/lowntfs-3g.c'; fi` + +ntfs_3g-ntfs-3g.o: ntfs-3g.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ntfs_3g_CFLAGS) $(CFLAGS) -MT ntfs_3g-ntfs-3g.o -MD -MP -MF $(DEPDIR)/ntfs_3g-ntfs-3g.Tpo -c -o ntfs_3g-ntfs-3g.o `test -f 'ntfs-3g.c' || echo '$(srcdir)/'`ntfs-3g.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/ntfs_3g-ntfs-3g.Tpo $(DEPDIR)/ntfs_3g-ntfs-3g.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='ntfs-3g.c' object='ntfs_3g-ntfs-3g.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ntfs_3g_CFLAGS) $(CFLAGS) -c -o ntfs_3g-ntfs-3g.o `test -f 'ntfs-3g.c' || echo '$(srcdir)/'`ntfs-3g.c + +ntfs_3g-ntfs-3g.obj: ntfs-3g.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ntfs_3g_CFLAGS) $(CFLAGS) -MT ntfs_3g-ntfs-3g.obj -MD -MP -MF $(DEPDIR)/ntfs_3g-ntfs-3g.Tpo -c -o ntfs_3g-ntfs-3g.obj `if test -f 'ntfs-3g.c'; then $(CYGPATH_W) 'ntfs-3g.c'; else $(CYGPATH_W) '$(srcdir)/ntfs-3g.c'; fi` +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/ntfs_3g-ntfs-3g.Tpo $(DEPDIR)/ntfs_3g-ntfs-3g.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='ntfs-3g.c' object='ntfs_3g-ntfs-3g.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ntfs_3g_CFLAGS) $(CFLAGS) -c -o ntfs_3g-ntfs-3g.obj `if test -f 'ntfs-3g.c'; then $(CYGPATH_W) 'ntfs-3g.c'; else $(CYGPATH_W) '$(srcdir)/ntfs-3g.c'; fi` + +ntfs_3g_probe-ntfs-3g.probe.o: ntfs-3g.probe.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ntfs_3g_probe_CFLAGS) $(CFLAGS) -MT ntfs_3g_probe-ntfs-3g.probe.o -MD -MP -MF $(DEPDIR)/ntfs_3g_probe-ntfs-3g.probe.Tpo -c -o ntfs_3g_probe-ntfs-3g.probe.o `test -f 'ntfs-3g.probe.c' || echo '$(srcdir)/'`ntfs-3g.probe.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/ntfs_3g_probe-ntfs-3g.probe.Tpo $(DEPDIR)/ntfs_3g_probe-ntfs-3g.probe.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='ntfs-3g.probe.c' object='ntfs_3g_probe-ntfs-3g.probe.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ntfs_3g_probe_CFLAGS) $(CFLAGS) -c -o ntfs_3g_probe-ntfs-3g.probe.o `test -f 'ntfs-3g.probe.c' || echo '$(srcdir)/'`ntfs-3g.probe.c + +ntfs_3g_probe-ntfs-3g.probe.obj: ntfs-3g.probe.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ntfs_3g_probe_CFLAGS) $(CFLAGS) -MT ntfs_3g_probe-ntfs-3g.probe.obj -MD -MP -MF $(DEPDIR)/ntfs_3g_probe-ntfs-3g.probe.Tpo -c -o ntfs_3g_probe-ntfs-3g.probe.obj `if test -f 'ntfs-3g.probe.c'; then $(CYGPATH_W) 'ntfs-3g.probe.c'; else $(CYGPATH_W) '$(srcdir)/ntfs-3g.probe.c'; fi` +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/ntfs_3g_probe-ntfs-3g.probe.Tpo $(DEPDIR)/ntfs_3g_probe-ntfs-3g.probe.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='ntfs-3g.probe.c' object='ntfs_3g_probe-ntfs-3g.probe.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ntfs_3g_probe_CFLAGS) $(CFLAGS) -c -o ntfs_3g_probe-ntfs-3g.probe.obj `if test -f 'ntfs-3g.probe.c'; then $(CYGPATH_W) 'ntfs-3g.probe.c'; else $(CYGPATH_W) '$(srcdir)/ntfs-3g.probe.c'; fi` + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-man8: $(man8_MANS) $(man_MANS) + @$(NORMAL_INSTALL) + test -z "$(man8dir)" || $(MKDIR_P) "$(DESTDIR)$(man8dir)" + @list='$(man8_MANS) $(dist_man8_MANS) $(nodist_man8_MANS)'; \ + l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ + for i in $$l2; do \ + case "$$i" in \ + *.8*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \ + else file=$$i; fi; \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + case "$$ext" in \ + 8*) ;; \ + *) ext='8' ;; \ + esac; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed -e 's/^.*\///'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man8dir)/$$inst'"; \ + $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man8dir)/$$inst"; \ + done +uninstall-man8: + @$(NORMAL_UNINSTALL) + @list='$(man8_MANS) $(dist_man8_MANS) $(nodist_man8_MANS)'; \ + l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ + for i in $$l2; do \ + case "$$i" in \ + *.8*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + case "$$ext" in \ + 8*) ;; \ + *) ext='8' ;; \ + esac; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed -e 's/^.*\///'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " rm -f '$(DESTDIR)$(man8dir)/$$inst'"; \ + rm -f "$(DESTDIR)$(man8dir)/$$inst"; \ + done +install-rootsbinDATA: $(rootsbin_DATA) + @$(NORMAL_INSTALL) + test -z "$(rootsbindir)" || $(MKDIR_P) "$(DESTDIR)$(rootsbindir)" + @list='$(rootsbin_DATA)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f=$(am__strip_dir) \ + echo " $(rootsbinDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(rootsbindir)/$$f'"; \ + $(rootsbinDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(rootsbindir)/$$f"; \ + done + +uninstall-rootsbinDATA: + @$(NORMAL_UNINSTALL) + @list='$(rootsbin_DATA)'; for p in $$list; do \ + f=$(am__strip_dir) \ + echo " rm -f '$(DESTDIR)$(rootsbindir)/$$f'"; \ + rm -f "$(DESTDIR)$(rootsbindir)/$$f"; \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(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 $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$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) $(MANS) $(DATA) +installdirs: + for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(rootbindir)" "$(DESTDIR)$(man8dir)" "$(DESTDIR)$(rootsbindir)"; 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: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) +@ENABLE_MOUNT_HELPER_FALSE@install-exec-local: +@RUN_LDCONFIG_FALSE@install-exec-hook: +clean: clean-am + +clean-am: clean-binPROGRAMS clean-generic clean-libtool \ + clean-rootbinPROGRAMS mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-data-local install-man \ + install-rootbinPROGRAMS install-rootsbinDATA + +install-dvi: install-dvi-am + +install-exec-am: install-binPROGRAMS install-exec-local + @$(NORMAL_INSTALL) + $(MAKE) $(AM_MAKEFLAGS) install-exec-hook + +install-html: install-html-am + +install-info: install-info-am + +install-man: install-man8 + +install-pdf: install-pdf-am + +install-ps: install-ps-am + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-binPROGRAMS uninstall-local uninstall-man \ + uninstall-rootbinPROGRAMS uninstall-rootsbinDATA + +uninstall-man: uninstall-man8 + +.MAKE: install-am install-exec-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \ + clean-generic clean-libtool clean-rootbinPROGRAMS ctags \ + distclean distclean-compile distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-binPROGRAMS \ + install-data install-data-am install-data-local install-dvi \ + install-dvi-am install-exec install-exec-am install-exec-hook \ + install-exec-local install-html install-html-am install-info \ + install-info-am install-man install-man8 install-pdf \ + install-pdf-am install-ps install-ps-am \ + install-rootbinPROGRAMS install-rootsbinDATA install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-binPROGRAMS \ + uninstall-local uninstall-man uninstall-man8 \ + uninstall-rootbinPROGRAMS uninstall-rootsbinDATA + + +@RUN_LDCONFIG_TRUE@install-exec-hook: +@RUN_LDCONFIG_TRUE@ $(LDCONFIG) + +@ENABLE_MOUNT_HELPER_TRUE@install-exec-local: install-rootbinPROGRAMS +@ENABLE_MOUNT_HELPER_TRUE@ $(MKDIR_P) "$(DESTDIR)/sbin" +@ENABLE_MOUNT_HELPER_TRUE@ $(LN_S) -f "$(rootbindir)/ntfs-3g" "$(DESTDIR)/sbin/mount.ntfs-3g" +@ENABLE_MOUNT_HELPER_TRUE@ $(LN_S) -f "$(rootbindir)/lowntfs-3g" "$(DESTDIR)/sbin/mount.lowntfs-3g" + +install-data-local: install-man8 + $(LN_S) -f ntfs-3g.8 "$(DESTDIR)$(man8dir)/mount.ntfs-3g.8" + $(LN_S) -f ntfs-3g.8 "$(DESTDIR)$(man8dir)/mount.lowntfs-3g.8" + +uninstall-local: + $(RM) -f "$(DESTDIR)$(man8dir)/mount.ntfs-3g.8" +@ENABLE_MOUNT_HELPER_TRUE@ $(RM) -f "$(DESTDIR)/sbin/mount.ntfs-3g" "$(DESTDIR)/sbin/mount.lowntfs-3g" +# 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: diff --git a/NEWS b/NEWS new file mode 100755 index 0000000..885ef59 --- a/dev/null +++ b/NEWS @@ -0,0 +1,5 @@ + +Project news are at http://www.ntfs-3g.org + +Release notes are maintained at http://www.ntfs-3g.org/releases.html + diff --git a/README b/README new file mode 100755 index 0000000..12328b3 --- a/dev/null +++ b/README @@ -0,0 +1,68 @@ + +INTRODUCTION +============ + +The NTFS-3G driver is an open source, freely available read/write NTFS driver +for Linux, FreeBSD, Mac OS X, NetBSD, OpenSolaris, QNX and Haiku. It provides +safe and fast handling of the Windows XP, Windows Server 2003, Windows 2000, +Windows Vista, Windows Server 2008 and Windows 7 file systems. + +The purpose of the project is to develop, quality assurance and support a +trustable, featureful and high performance solution for hardware platforms +and operating systems whose users need to reliably interoperate with NTFS. +Besides this practical goal, the project also aims to explore the limits +of the hybrid, kernel/user space filesystem driver approach, performance, +reliability and feature richness per invested effort wise. + +Besides the common file system features, NTFS-3G has support for file +ownership and permissions, POSIX ACLs, junction points, extended attributes +and creating compressed files. Parameter files in the directory .NTFS-3G may +be required to enable them, please get the instructions from + + http://www.tuxera.com/community/ntfs-3g-advanced/ + +News, support answers, problem submission instructions, support and discussion +forums, performance numbers and other information are available on the project +web site at + + http://www.tuxera.com/community/ + + +QUICK INSTALLATION +================== + +Linux: Make sure you have the basic development tools and the kernel includes +the FUSE kernel module. Then unpack the source tarball and type: + + ./configure + make + make install # or 'sudo make install' if you aren't root. + +Please note that NTFS-3G doesn't require the FUSE user space package. + +Non-Linux: Please see + + http://www.tuxera.com/community/ntfs-3g-download/ + +for OS specific installation and source packages. + + +USAGE +===== + +If there was no error during installation then the NTFS volume can be +read-write mounted for everybody the following way as the root user +(unmount the volume if it was already mounted, and replace /dev/sda1 +and /mnt/windows, if needed): + + mount -t ntfs-3g /dev/sda1 /mnt/windows +or + ntfs-3g /dev/sda1 /mnt/windows + +Please see the ntfs-3g manual page for more options and examples. + +You can also make NTFS to be mounted during boot by putting the below +line at the END(!) of the /etc/fstab file: + + /dev/sda1 /mnt/windows ntfs-3g defaults 0 0 + diff --git a/aclocal.m4 b/aclocal.m4 new file mode 100755 index 0000000..1379c10 --- a/dev/null +++ b/aclocal.m4 @@ -0,0 +1,7723 @@ +# generated automatically by aclocal 1.10.1 -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, +# 2005, 2006, 2007, 2008 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_AUTOCONF_VERSION], + [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl +m4_if(AC_AUTOCONF_VERSION, [2.61],, +[m4_warning([this file was generated for autoconf 2.61. +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'.])]) + +# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*- + +# serial 52 AC_PROG_LIBTOOL + + +# AC_PROVIDE_IFELSE(MACRO-NAME, IF-PROVIDED, IF-NOT-PROVIDED) +# ----------------------------------------------------------- +# If this macro is not defined by Autoconf, define it here. +m4_ifdef([AC_PROVIDE_IFELSE], + [], + [m4_define([AC_PROVIDE_IFELSE], + [m4_ifdef([AC_PROVIDE_$1], + [$2], [$3])])]) + + +# AC_PROG_LIBTOOL +# --------------- +AC_DEFUN([AC_PROG_LIBTOOL], +[AC_REQUIRE([_AC_PROG_LIBTOOL])dnl +dnl If AC_PROG_CXX has already been expanded, run AC_LIBTOOL_CXX +dnl immediately, otherwise, hook it in at the end of AC_PROG_CXX. + AC_PROVIDE_IFELSE([AC_PROG_CXX], + [AC_LIBTOOL_CXX], + [define([AC_PROG_CXX], defn([AC_PROG_CXX])[AC_LIBTOOL_CXX + ])]) +dnl And a similar setup for Fortran 77 support + AC_PROVIDE_IFELSE([AC_PROG_F77], + [AC_LIBTOOL_F77], + [define([AC_PROG_F77], defn([AC_PROG_F77])[AC_LIBTOOL_F77 +])]) + +dnl Quote A][M_PROG_GCJ so that aclocal doesn't bring it in needlessly. +dnl If either AC_PROG_GCJ or A][M_PROG_GCJ have already been expanded, run +dnl AC_LIBTOOL_GCJ immediately, otherwise, hook it in at the end of both. + AC_PROVIDE_IFELSE([AC_PROG_GCJ], + [AC_LIBTOOL_GCJ], + [AC_PROVIDE_IFELSE([A][M_PROG_GCJ], + [AC_LIBTOOL_GCJ], + [AC_PROVIDE_IFELSE([LT_AC_PROG_GCJ], + [AC_LIBTOOL_GCJ], + [ifdef([AC_PROG_GCJ], + [define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[AC_LIBTOOL_GCJ])]) + ifdef([A][M_PROG_GCJ], + [define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[AC_LIBTOOL_GCJ])]) + ifdef([LT_AC_PROG_GCJ], + [define([LT_AC_PROG_GCJ], + defn([LT_AC_PROG_GCJ])[AC_LIBTOOL_GCJ])])])]) +])])# AC_PROG_LIBTOOL + + +# _AC_PROG_LIBTOOL +# ---------------- +AC_DEFUN([_AC_PROG_LIBTOOL], +[AC_REQUIRE([AC_LIBTOOL_SETUP])dnl +AC_BEFORE([$0],[AC_LIBTOOL_CXX])dnl +AC_BEFORE([$0],[AC_LIBTOOL_F77])dnl +AC_BEFORE([$0],[AC_LIBTOOL_GCJ])dnl + +# This can be used to rebuild libtool when needed +LIBTOOL_DEPS="$ac_aux_dir/ltmain.sh" + +# Always use our own libtool. +LIBTOOL='$(SHELL) $(top_builddir)/libtool' +AC_SUBST(LIBTOOL)dnl + +# Prevent multiple expansion +define([AC_PROG_LIBTOOL], []) +])# _AC_PROG_LIBTOOL + + +# AC_LIBTOOL_SETUP +# ---------------- +AC_DEFUN([AC_LIBTOOL_SETUP], +[AC_PREREQ(2.50)dnl +AC_REQUIRE([AC_ENABLE_SHARED])dnl +AC_REQUIRE([AC_ENABLE_STATIC])dnl +AC_REQUIRE([AC_ENABLE_FAST_INSTALL])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_PROG_LD])dnl +AC_REQUIRE([AC_PROG_LD_RELOAD_FLAG])dnl +AC_REQUIRE([AC_PROG_NM])dnl + +AC_REQUIRE([AC_PROG_LN_S])dnl +AC_REQUIRE([AC_DEPLIBS_CHECK_METHOD])dnl +# Autoconf 2.13's AC_OBJEXT and AC_EXEEXT macros only works for C compilers! +AC_REQUIRE([AC_OBJEXT])dnl +AC_REQUIRE([AC_EXEEXT])dnl +dnl +AC_LIBTOOL_SYS_MAX_CMD_LEN +AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE +AC_LIBTOOL_OBJDIR + +AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl +_LT_AC_PROG_ECHO_BACKSLASH + +case $host_os in +aix3*) + # AIX sometimes has problems with the GCC collect2 program. For some + # reason, if we set the COLLECT_NAMES environment variable, the problems + # vanish in a puff of smoke. + if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES + fi + ;; +esac + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +Xsed='sed -e 1s/^X//' +[sed_quote_subst='s/\([\\"\\`$\\\\]\)/\\\1/g'] + +# Same as above, but do not quote variable references. +[double_quote_subst='s/\([\\"\\`\\\\]\)/\\\1/g'] + +# Sed substitution to delay expansion of an escaped shell variable in a +# double_quote_subst'ed string. +delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' + +# Sed substitution to avoid accidental globbing in evaled expressions +no_glob_subst='s/\*/\\\*/g' + +# Constants: +rm="rm -f" + +# Global variables: +default_ofile=libtool +can_build_shared=yes + +# All known linkers require a `.a' archive for static linking (except MSVC, +# which needs '.lib'). +libext=a +ltmain="$ac_aux_dir/ltmain.sh" +ofile="$default_ofile" +with_gnu_ld="$lt_cv_prog_gnu_ld" + +AC_CHECK_TOOL(AR, ar, false) +AC_CHECK_TOOL(RANLIB, ranlib, :) +AC_CHECK_TOOL(STRIP, strip, :) + +old_CC="$CC" +old_CFLAGS="$CFLAGS" + +# Set sane defaults for various variables +test -z "$AR" && AR=ar +test -z "$AR_FLAGS" && AR_FLAGS=cru +test -z "$AS" && AS=as +test -z "$CC" && CC=cc +test -z "$LTCC" && LTCC=$CC +test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS +test -z "$DLLTOOL" && DLLTOOL=dlltool +test -z "$LD" && LD=ld +test -z "$LN_S" && LN_S="ln -s" +test -z "$MAGIC_CMD" && MAGIC_CMD=file +test -z "$NM" && NM=nm +test -z "$SED" && SED=sed +test -z "$OBJDUMP" && OBJDUMP=objdump +test -z "$RANLIB" && RANLIB=: +test -z "$STRIP" && STRIP=: +test -z "$ac_objext" && ac_objext=o + +# Determine commands to create old-style static archives. +old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' +old_postinstall_cmds='chmod 644 $oldlib' +old_postuninstall_cmds= + +if test -n "$RANLIB"; then + case $host_os in + openbsd*) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$oldlib" + ;; + *) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$oldlib" + ;; + esac + old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib" +fi + +_LT_CC_BASENAME([$compiler]) + +# Only perform the check for file, if the check method requires it +case $deplibs_check_method in +file_magic*) + if test "$file_magic_cmd" = '$MAGIC_CMD'; then + AC_PATH_MAGIC + fi + ;; +esac + +_LT_REQUIRED_DARWIN_CHECKS + +AC_PROVIDE_IFELSE([AC_LIBTOOL_DLOPEN], enable_dlopen=yes, enable_dlopen=no) +AC_PROVIDE_IFELSE([AC_LIBTOOL_WIN32_DLL], +enable_win32_dll=yes, enable_win32_dll=no) + +AC_ARG_ENABLE([libtool-lock], + [AC_HELP_STRING([--disable-libtool-lock], + [avoid locking (might break parallel builds)])]) +test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes + +AC_ARG_WITH([pic], + [AC_HELP_STRING([--with-pic], + [try to use only PIC/non-PIC objects @<:@default=use both@:>@])], + [pic_mode="$withval"], + [pic_mode=default]) +test -z "$pic_mode" && pic_mode=default + +# Use C for the default configuration in the libtool script +tagname= +AC_LIBTOOL_LANG_C_CONFIG +_LT_AC_TAGCONFIG +])# AC_LIBTOOL_SETUP + + +# _LT_AC_SYS_COMPILER +# ------------------- +AC_DEFUN([_LT_AC_SYS_COMPILER], +[AC_REQUIRE([AC_PROG_CC])dnl + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC +])# _LT_AC_SYS_COMPILER + + +# _LT_CC_BASENAME(CC) +# ------------------- +# Calculate cc_basename. Skip known compiler wrappers and cross-prefix. +AC_DEFUN([_LT_CC_BASENAME], +[for cc_temp in $1""; do + case $cc_temp in + compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;; + distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`$echo "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"` +]) + + +# _LT_COMPILER_BOILERPLATE +# ------------------------ +# Check for compiler boilerplate output or warnings with +# the simple compiler test code. +AC_DEFUN([_LT_COMPILER_BOILERPLATE], +[AC_REQUIRE([LT_AC_PROG_SED])dnl +ac_outfile=conftest.$ac_objext +echo "$lt_simple_compile_test_code" >conftest.$ac_ext +eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_compiler_boilerplate=`cat conftest.err` +$rm conftest* +])# _LT_COMPILER_BOILERPLATE + + +# _LT_LINKER_BOILERPLATE +# ---------------------- +# Check for linker boilerplate output or warnings with +# the simple link test code. +AC_DEFUN([_LT_LINKER_BOILERPLATE], +[AC_REQUIRE([LT_AC_PROG_SED])dnl +ac_outfile=conftest.$ac_objext +echo "$lt_simple_link_test_code" >conftest.$ac_ext +eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_linker_boilerplate=`cat conftest.err` +$rm -r conftest* +])# _LT_LINKER_BOILERPLATE + +# _LT_REQUIRED_DARWIN_CHECKS +# -------------------------- +# Check for some things on darwin +AC_DEFUN([_LT_REQUIRED_DARWIN_CHECKS],[ + case $host_os in + rhapsody* | darwin*) + AC_CHECK_TOOL([DSYMUTIL], [dsymutil], [:]) + AC_CHECK_TOOL([NMEDIT], [nmedit], [:]) + + AC_CACHE_CHECK([for -single_module linker flag],[lt_cv_apple_cc_single_mod], + [lt_cv_apple_cc_single_mod=no + if test -z "${LT_MULTI_MODULE}"; then + # By default we will add the -single_module flag. You can override + # by either setting the environment variable LT_MULTI_MODULE + # non-empty at configure time, or by adding -multi_module to the + # link flags. + echo "int foo(void){return 1;}" > conftest.c + $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ + -dynamiclib ${wl}-single_module conftest.c + if test -f libconftest.dylib; then + lt_cv_apple_cc_single_mod=yes + rm -rf libconftest.dylib* + fi + rm conftest.c + fi]) + AC_CACHE_CHECK([for -exported_symbols_list linker flag], + [lt_cv_ld_exported_symbols_list], + [lt_cv_ld_exported_symbols_list=no + save_LDFLAGS=$LDFLAGS + echo "_main" > conftest.sym + LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" + AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], + [lt_cv_ld_exported_symbols_list=yes], + [lt_cv_ld_exported_symbols_list=no]) + LDFLAGS="$save_LDFLAGS" + ]) + case $host_os in + rhapsody* | darwin1.[[0123]]) + _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;; + darwin1.*) + _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; + darwin*) + # if running on 10.5 or later, the deployment target defaults + # to the OS version, if on x86, and 10.4, the deployment + # target defaults to 10.4. Don't you love it? + case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in + 10.0,*86*-darwin8*|10.0,*-darwin[[91]]*) + _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; + 10.[[012]]*) + _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; + 10.*) + _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; + esac + ;; + esac + if test "$lt_cv_apple_cc_single_mod" = "yes"; then + _lt_dar_single_mod='$single_module' + fi + if test "$lt_cv_ld_exported_symbols_list" = "yes"; then + _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym' + else + _lt_dar_export_syms="~$NMEDIT -s \$output_objdir/\${libname}-symbols.expsym \${lib}" + fi + if test "$DSYMUTIL" != ":"; then + _lt_dsymutil="~$DSYMUTIL \$lib || :" + else + _lt_dsymutil= + fi + ;; + esac +]) + +# _LT_AC_SYS_LIBPATH_AIX +# ---------------------- +# Links a minimal program and checks the executable +# for the system default hardcoded library path. In most cases, +# this is /usr/lib:/lib, but when the MPI compilers are used +# the location of the communication and MPI libs are included too. +# If we don't find anything, use the default library path according +# to the aix ld manual. +AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX], +[AC_REQUIRE([LT_AC_PROG_SED])dnl +AC_LINK_IFELSE(AC_LANG_PROGRAM,[ +lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\(.*\)$/\1/ + p + } + }' +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then + aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +fi],[]) +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi +])# _LT_AC_SYS_LIBPATH_AIX + + +# _LT_AC_SHELL_INIT(ARG) +# ---------------------- +AC_DEFUN([_LT_AC_SHELL_INIT], +[ifdef([AC_DIVERSION_NOTICE], + [AC_DIVERT_PUSH(AC_DIVERSION_NOTICE)], + [AC_DIVERT_PUSH(NOTICE)]) +$1 +AC_DIVERT_POP +])# _LT_AC_SHELL_INIT + + +# _LT_AC_PROG_ECHO_BACKSLASH +# -------------------------- +# Add some code to the start of the generated configure script which +# will find an echo command which doesn't interpret backslashes. +AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH], +[_LT_AC_SHELL_INIT([ +# Check that we are running under the correct shell. +SHELL=${CONFIG_SHELL-/bin/sh} + +case X$ECHO in +X*--fallback-echo) + # Remove one level of quotation (which was required for Make). + ECHO=`echo "$ECHO" | sed 's,\\\\\[$]\\[$]0,'[$]0','` + ;; +esac + +echo=${ECHO-echo} +if test "X[$]1" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift +elif test "X[$]1" = X--fallback-echo; then + # Avoid inline document here, it may be left over + : +elif test "X`($echo '\t') 2>/dev/null`" = 'X\t' ; then + # Yippee, $echo works! + : +else + # Restart under the correct shell. + exec $SHELL "[$]0" --no-reexec ${1+"[$]@"} +fi + +if test "X[$]1" = X--fallback-echo; then + # used as fallback echo + shift + cat </dev/null 2>&1 && unset CDPATH + +if test -z "$ECHO"; then +if test "X${echo_test_string+set}" != Xset; then +# find a string as large as possible, as long as the shell can cope with it + for cmd in 'sed 50q "[$]0"' 'sed 20q "[$]0"' 'sed 10q "[$]0"' 'sed 2q "[$]0"' 'echo test'; do + # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ... + if (echo_test_string=`eval $cmd`) 2>/dev/null && + echo_test_string=`eval $cmd` && + (test "X$echo_test_string" = "X$echo_test_string") 2>/dev/null + then + break + fi + done +fi + +if test "X`($echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + : +else + # The Solaris, AIX, and Digital Unix default echo programs unquote + # backslashes. This makes it impossible to quote backslashes using + # echo "$something" | sed 's/\\/\\\\/g' + # + # So, first we look for a working echo in the user's PATH. + + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for dir in $PATH /usr/ucb; do + IFS="$lt_save_ifs" + if (test -f $dir/echo || test -f $dir/echo$ac_exeext) && + test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + echo="$dir/echo" + break + fi + done + IFS="$lt_save_ifs" + + if test "X$echo" = Xecho; then + # We didn't find a better echo, so look for alternatives. + if test "X`(print -r '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`(print -r "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + # This shell has a builtin print -r that does the trick. + echo='print -r' + elif (test -f /bin/ksh || test -f /bin/ksh$ac_exeext) && + test "X$CONFIG_SHELL" != X/bin/ksh; then + # If we have ksh, try running configure again with it. + ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh} + export ORIGINAL_CONFIG_SHELL + CONFIG_SHELL=/bin/ksh + export CONFIG_SHELL + exec $CONFIG_SHELL "[$]0" --no-reexec ${1+"[$]@"} + else + # Try using printf. + echo='printf %s\n' + if test "X`($echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + # Cool, printf works + : + elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL + export CONFIG_SHELL + SHELL="$CONFIG_SHELL" + export SHELL + echo="$CONFIG_SHELL [$]0 --fallback-echo" + elif echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + echo="$CONFIG_SHELL [$]0 --fallback-echo" + else + # maybe with a smaller string... + prev=: + + for cmd in 'echo test' 'sed 2q "[$]0"' 'sed 10q "[$]0"' 'sed 20q "[$]0"' 'sed 50q "[$]0"'; do + if (test "X$echo_test_string" = "X`eval $cmd`") 2>/dev/null + then + break + fi + prev="$cmd" + done + + if test "$prev" != 'sed 50q "[$]0"'; then + echo_test_string=`eval $prev` + export echo_test_string + exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "[$]0" ${1+"[$]@"} + else + # Oops. We lost completely, so just stick with echo. + echo=echo + fi + fi + fi + fi +fi +fi + +# Copy echo and quote the copy suitably for passing to libtool from +# the Makefile, instead of quoting the original, which is used later. +ECHO=$echo +if test "X$ECHO" = "X$CONFIG_SHELL [$]0 --fallback-echo"; then + ECHO="$CONFIG_SHELL \\\$\[$]0 --fallback-echo" +fi + +AC_SUBST(ECHO) +])])# _LT_AC_PROG_ECHO_BACKSLASH + + +# _LT_AC_LOCK +# ----------- +AC_DEFUN([_LT_AC_LOCK], +[AC_ARG_ENABLE([libtool-lock], + [AC_HELP_STRING([--disable-libtool-lock], + [avoid locking (might break parallel builds)])]) +test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes + +# Some flags need to be propagated to the compiler or linker for good +# libtool support. +case $host in +ia64-*-hpux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.$ac_objext` in + *ELF-32*) + HPUX_IA64_MODE="32" + ;; + *ELF-64*) + HPUX_IA64_MODE="64" + ;; + esac + fi + rm -rf conftest* + ;; +*-*-irix6*) + # Find out which ABI we are using. + echo '[#]line __oline__ "configure"' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + if test "$lt_cv_prog_gnu_ld" = yes; then + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -melf32bsmip" + ;; + *N32*) + LD="${LD-ld} -melf32bmipn32" + ;; + *64-bit*) + LD="${LD-ld} -melf64bmip" + ;; + esac + else + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -32" + ;; + *N32*) + LD="${LD-ld} -n32" + ;; + *64-bit*) + LD="${LD-ld} -64" + ;; + esac + fi + fi + rm -rf conftest* + ;; + +x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \ +s390*-*linux*|sparc*-*linux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.o` in + *32-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_i386_fbsd" + ;; + x86_64-*linux*) + LD="${LD-ld} -m elf_i386" + ;; + ppc64-*linux*|powerpc64-*linux*) + LD="${LD-ld} -m elf32ppclinux" + ;; + s390x-*linux*) + LD="${LD-ld} -m elf_s390" + ;; + sparc64-*linux*) + LD="${LD-ld} -m elf32_sparc" + ;; + esac + ;; + *64-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_x86_64_fbsd" + ;; + x86_64-*linux*) + LD="${LD-ld} -m elf_x86_64" + ;; + ppc*-*linux*|powerpc*-*linux*) + LD="${LD-ld} -m elf64ppc" + ;; + s390*-*linux*) + LD="${LD-ld} -m elf64_s390" + ;; + sparc*-*linux*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; + +*-*-sco3.2v5*) + # On SCO OpenServer 5, we need -belf to get full-featured binaries. + SAVE_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -belf" + AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf, + [AC_LANG_PUSH(C) + AC_TRY_LINK([],[],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no]) + AC_LANG_POP]) + if test x"$lt_cv_cc_needs_belf" != x"yes"; then + # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf + CFLAGS="$SAVE_CFLAGS" + fi + ;; +sparc*-*solaris*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.o` in + *64-bit*) + case $lt_cv_prog_gnu_ld in + yes*) LD="${LD-ld} -m elf64_sparc" ;; + *) + if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then + LD="${LD-ld} -64" + fi + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; + +AC_PROVIDE_IFELSE([AC_LIBTOOL_WIN32_DLL], +[*-*-cygwin* | *-*-mingw* | *-*-pw32*) + AC_CHECK_TOOL(DLLTOOL, dlltool, false) + AC_CHECK_TOOL(AS, as, false) + AC_CHECK_TOOL(OBJDUMP, objdump, false) + ;; + ]) +esac + +need_locks="$enable_libtool_lock" + +])# _LT_AC_LOCK + + +# AC_LIBTOOL_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, +# [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE]) +# ---------------------------------------------------------------- +# Check whether the given compiler option works +AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], +[AC_REQUIRE([LT_AC_PROG_SED]) +AC_CACHE_CHECK([$1], [$2], + [$2=no + ifelse([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4]) + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$3" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&AS_MESSAGE_LOG_FD + echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + $2=yes + fi + fi + $rm conftest* +]) + +if test x"[$]$2" = xyes; then + ifelse([$5], , :, [$5]) +else + ifelse([$6], , :, [$6]) +fi +])# AC_LIBTOOL_COMPILER_OPTION + + +# AC_LIBTOOL_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, +# [ACTION-SUCCESS], [ACTION-FAILURE]) +# ------------------------------------------------------------ +# Check whether the given compiler option works +AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], +[AC_REQUIRE([LT_AC_PROG_SED])dnl +AC_CACHE_CHECK([$1], [$2], + [$2=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $3" + echo "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&AS_MESSAGE_LOG_FD + $echo "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + $2=yes + fi + else + $2=yes + fi + fi + $rm -r conftest* + LDFLAGS="$save_LDFLAGS" +]) + +if test x"[$]$2" = xyes; then + ifelse([$4], , :, [$4]) +else + ifelse([$5], , :, [$5]) +fi +])# AC_LIBTOOL_LINKER_OPTION + + +# AC_LIBTOOL_SYS_MAX_CMD_LEN +# -------------------------- +AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], +[# find the maximum length of command line arguments +AC_MSG_CHECKING([the maximum length of command line arguments]) +AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl + i=0 + teststring="ABCD" + + case $build_os in + msdosdjgpp*) + # On DJGPP, this test can blow up pretty badly due to problems in libc + # (any single argument exceeding 2000 bytes causes a buffer overrun + # during glob expansion). Even if it were fixed, the result of this + # check would be larger than it should be. + lt_cv_sys_max_cmd_len=12288; # 12K is about right + ;; + + gnu*) + # Under GNU Hurd, this test is not required because there is + # no limit to the length of command line arguments. + # Libtool will interpret -1 as no limit whatsoever + lt_cv_sys_max_cmd_len=-1; + ;; + + cygwin* | mingw*) + # On Win9x/ME, this test blows up -- it succeeds, but takes + # about 5 minutes as the teststring grows exponentially. + # Worse, since 9x/ME are not pre-emptively multitasking, + # you end up with a "frozen" computer, even though with patience + # the test eventually succeeds (with a max line length of 256k). + # Instead, let's just punt: use the minimum linelength reported by + # all of the supported platforms: 8192 (on NT/2K/XP). + lt_cv_sys_max_cmd_len=8192; + ;; + + amigaos*) + # On AmigaOS with pdksh, this test takes hours, literally. + # So we just punt and use a minimum line length of 8192. + lt_cv_sys_max_cmd_len=8192; + ;; + + netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) + # This has been around since 386BSD, at least. Likely further. + if test -x /sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` + elif test -x /usr/sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` + else + lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs + fi + # And add a safety zone + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + ;; + + interix*) + # We know the value 262144 and hardcode it with a safety zone (like BSD) + lt_cv_sys_max_cmd_len=196608 + ;; + + osf*) + # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure + # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not + # nice to cause kernel panics so lets avoid the loop below. + # First set a reasonable default. + lt_cv_sys_max_cmd_len=16384 + # + if test -x /sbin/sysconfig; then + case `/sbin/sysconfig -q proc exec_disable_arg_limit` in + *1*) lt_cv_sys_max_cmd_len=-1 ;; + esac + fi + ;; + sco3.2v5*) + lt_cv_sys_max_cmd_len=102400 + ;; + sysv5* | sco5v6* | sysv4.2uw2*) + kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` + if test -n "$kargmax"; then + lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[ ]]//'` + else + lt_cv_sys_max_cmd_len=32768 + fi + ;; + *) + lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` + if test -n "$lt_cv_sys_max_cmd_len"; then + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + else + SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} + while (test "X"`$SHELL [$]0 --fallback-echo "X$teststring" 2>/dev/null` \ + = "XX$teststring") >/dev/null 2>&1 && + new_result=`expr "X$teststring" : ".*" 2>&1` && + lt_cv_sys_max_cmd_len=$new_result && + test $i != 17 # 1/2 MB should be enough + do + i=`expr $i + 1` + teststring=$teststring$teststring + done + teststring= + # Add a significant safety factor because C++ compilers can tack on massive + # amounts of additional arguments before passing them to the linker. + # It appears as though 1/2 is a usable value. + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` + fi + ;; + esac +]) +if test -n $lt_cv_sys_max_cmd_len ; then + AC_MSG_RESULT($lt_cv_sys_max_cmd_len) +else + AC_MSG_RESULT(none) +fi +])# AC_LIBTOOL_SYS_MAX_CMD_LEN + + +# _LT_AC_CHECK_DLFCN +# ------------------ +AC_DEFUN([_LT_AC_CHECK_DLFCN], +[AC_CHECK_HEADERS(dlfcn.h)dnl +])# _LT_AC_CHECK_DLFCN + + +# _LT_AC_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE, +# ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING) +# --------------------------------------------------------------------- +AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF], +[AC_REQUIRE([_LT_AC_CHECK_DLFCN])dnl +if test "$cross_compiling" = yes; then : + [$4] +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext < +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +#ifdef __cplusplus +extern "C" void exit (int); +#endif + +void fnord() { int i=42;} +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + /* dlclose (self); */ + } + else + puts (dlerror ()); + + exit (status); +}] +EOF + if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) $1 ;; + x$lt_dlneed_uscore) $2 ;; + x$lt_dlunknown|x*) $3 ;; + esac + else : + # compilation failed + $3 + fi +fi +rm -fr conftest* +])# _LT_AC_TRY_DLOPEN_SELF + + +# AC_LIBTOOL_DLOPEN_SELF +# ---------------------- +AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], +[AC_REQUIRE([_LT_AC_CHECK_DLFCN])dnl +if test "x$enable_dlopen" != xyes; then + enable_dlopen=unknown + enable_dlopen_self=unknown + enable_dlopen_self_static=unknown +else + lt_cv_dlopen=no + lt_cv_dlopen_libs= + + case $host_os in + beos*) + lt_cv_dlopen="load_add_on" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ;; + + mingw* | pw32*) + lt_cv_dlopen="LoadLibrary" + lt_cv_dlopen_libs= + ;; + + cygwin*) + lt_cv_dlopen="dlopen" + lt_cv_dlopen_libs= + ;; + + darwin*) + # if libdl is installed we need to link against it + AC_CHECK_LIB([dl], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[ + lt_cv_dlopen="dyld" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ]) + ;; + + *) + AC_CHECK_FUNC([shl_load], + [lt_cv_dlopen="shl_load"], + [AC_CHECK_LIB([dld], [shl_load], + [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld"], + [AC_CHECK_FUNC([dlopen], + [lt_cv_dlopen="dlopen"], + [AC_CHECK_LIB([dl], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"], + [AC_CHECK_LIB([svld], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"], + [AC_CHECK_LIB([dld], [dld_link], + [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld"]) + ]) + ]) + ]) + ]) + ]) + ;; + esac + + if test "x$lt_cv_dlopen" != xno; then + enable_dlopen=yes + else + enable_dlopen=no + fi + + case $lt_cv_dlopen in + dlopen) + save_CPPFLAGS="$CPPFLAGS" + test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" + + save_LDFLAGS="$LDFLAGS" + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" + + save_LIBS="$LIBS" + LIBS="$lt_cv_dlopen_libs $LIBS" + + AC_CACHE_CHECK([whether a program can dlopen itself], + lt_cv_dlopen_self, [dnl + _LT_AC_TRY_DLOPEN_SELF( + lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes, + lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross) + ]) + + if test "x$lt_cv_dlopen_self" = xyes; then + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" + AC_CACHE_CHECK([whether a statically linked program can dlopen itself], + lt_cv_dlopen_self_static, [dnl + _LT_AC_TRY_DLOPEN_SELF( + lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes, + lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross) + ]) + fi + + CPPFLAGS="$save_CPPFLAGS" + LDFLAGS="$save_LDFLAGS" + LIBS="$save_LIBS" + ;; + esac + + case $lt_cv_dlopen_self in + yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; + *) enable_dlopen_self=unknown ;; + esac + + case $lt_cv_dlopen_self_static in + yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; + *) enable_dlopen_self_static=unknown ;; + esac +fi +])# AC_LIBTOOL_DLOPEN_SELF + + +# AC_LIBTOOL_PROG_CC_C_O([TAGNAME]) +# --------------------------------- +# Check to see if options -c and -o are simultaneously supported by compiler +AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O], +[AC_REQUIRE([LT_AC_PROG_SED])dnl +AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl +AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext], + [_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)], + [_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no + $rm -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&AS_MESSAGE_LOG_FD + echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + _LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes + fi + fi + chmod u+w . 2>&AS_MESSAGE_LOG_FD + $rm conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $rm out/ii_files/* && rmdir out/ii_files + $rm out/* && rmdir out + cd .. + rmdir conftest + $rm conftest* +]) +])# AC_LIBTOOL_PROG_CC_C_O + + +# AC_LIBTOOL_SYS_HARD_LINK_LOCKS([TAGNAME]) +# ----------------------------------------- +# Check to see if we can do hard links to lock some files if needed +AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], +[AC_REQUIRE([_LT_AC_LOCK])dnl + +hard_links="nottested" +if test "$_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then + # do not overwrite the value of need_locks provided by the user + AC_MSG_CHECKING([if we can lock with hard links]) + hard_links=yes + $rm conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + AC_MSG_RESULT([$hard_links]) + if test "$hard_links" = no; then + AC_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe]) + need_locks=warn + fi +else + need_locks=no +fi +])# AC_LIBTOOL_SYS_HARD_LINK_LOCKS + + +# AC_LIBTOOL_OBJDIR +# ----------------- +AC_DEFUN([AC_LIBTOOL_OBJDIR], +[AC_CACHE_CHECK([for objdir], [lt_cv_objdir], +[rm -f .libs 2>/dev/null +mkdir .libs 2>/dev/null +if test -d .libs; then + lt_cv_objdir=.libs +else + # MS-DOS does not allow filenames that begin with a dot. + lt_cv_objdir=_libs +fi +rmdir .libs 2>/dev/null]) +objdir=$lt_cv_objdir +])# AC_LIBTOOL_OBJDIR + + +# AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH([TAGNAME]) +# ---------------------------------------------- +# Check hardcoding attributes. +AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], +[AC_MSG_CHECKING([how to hardcode library paths into programs]) +_LT_AC_TAGVAR(hardcode_action, $1)= +if test -n "$_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)" || \ + test -n "$_LT_AC_TAGVAR(runpath_var, $1)" || \ + test "X$_LT_AC_TAGVAR(hardcode_automatic, $1)" = "Xyes" ; then + + # We can hardcode non-existant directories. + if test "$_LT_AC_TAGVAR(hardcode_direct, $1)" != no && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test "$_LT_AC_TAGVAR(hardcode_shlibpath_var, $1)" != no && + test "$_LT_AC_TAGVAR(hardcode_minus_L, $1)" != no; then + # Linking always hardcodes the temporary library directory. + _LT_AC_TAGVAR(hardcode_action, $1)=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + _LT_AC_TAGVAR(hardcode_action, $1)=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + _LT_AC_TAGVAR(hardcode_action, $1)=unsupported +fi +AC_MSG_RESULT([$_LT_AC_TAGVAR(hardcode_action, $1)]) + +if test "$_LT_AC_TAGVAR(hardcode_action, $1)" = relink; then + # Fast installation is not supported + enable_fast_install=no +elif test "$shlibpath_overrides_runpath" = yes || + test "$enable_shared" = no; then + # Fast installation is not necessary + enable_fast_install=needless +fi +])# AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH + + +# AC_LIBTOOL_SYS_LIB_STRIP +# ------------------------ +AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP], +[striplib= +old_striplib= +AC_MSG_CHECKING([whether stripping libraries is possible]) +if test -n "$STRIP" && $STRIP -V 2>&1 | grep "GNU strip" >/dev/null; then + test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" + test -z "$striplib" && striplib="$STRIP --strip-unneeded" + AC_MSG_RESULT([yes]) +else +# FIXME - insert some real tests, host_os isn't really good enough + case $host_os in + darwin*) + if test -n "$STRIP" ; then + striplib="$STRIP -x" + old_striplib="$STRIP -S" + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) +fi + ;; + *) + AC_MSG_RESULT([no]) + ;; + esac +fi +])# AC_LIBTOOL_SYS_LIB_STRIP + + +# AC_LIBTOOL_SYS_DYNAMIC_LINKER +# ----------------------------- +# PORTME Fill in your ld.so characteristics +AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER], +[AC_REQUIRE([LT_AC_PROG_SED])dnl +AC_MSG_CHECKING([dynamic linker characteristics]) +library_names_spec= +libname_spec='lib$name' +soname_spec= +shrext_cmds=".so" +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +m4_if($1,[],[ +if test "$GCC" = yes; then + case $host_os in + darwin*) lt_awk_arg="/^libraries:/,/LR/" ;; + *) lt_awk_arg="/^libraries:/" ;; + esac + lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if echo "$lt_search_path_spec" | grep ';' >/dev/null ; then + # if the path contains ";" then we assume it to be the separator + # otherwise default to the standard path separator (i.e. ":") - it is + # assumed that no part of a normal pathname contains ";" but that should + # okay in the real world where ";" in dirpaths is itself problematic. + lt_search_path_spec=`echo "$lt_search_path_spec" | $SED -e 's/;/ /g'` + else + lt_search_path_spec=`echo "$lt_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + # Ok, now we have the path, separated by spaces, we can step through it + # and add multilib dir if necessary. + lt_tmp_lt_search_path_spec= + lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` + for lt_sys_path in $lt_search_path_spec; do + if test -d "$lt_sys_path/$lt_multi_os_dir"; then + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir" + else + test -d "$lt_sys_path" && \ + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" + fi + done + lt_search_path_spec=`echo $lt_tmp_lt_search_path_spec | awk ' +BEGIN {RS=" "; FS="/|\n";} { + lt_foo=""; + lt_count=0; + for (lt_i = NF; lt_i > 0; lt_i--) { + if ($lt_i != "" && $lt_i != ".") { + if ($lt_i == "..") { + lt_count++; + } else { + if (lt_count == 0) { + lt_foo="/" $lt_i lt_foo; + } else { + lt_count--; + } + } + } + } + if (lt_foo != "") { lt_freq[[lt_foo]]++; } + if (lt_freq[[lt_foo]] == 1) { print lt_foo; } +}'` + sys_lib_search_path_spec=`echo $lt_search_path_spec` +else + sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" +fi]) +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + +case $host_os in +aix3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='${libname}${release}${shared_ext}$major' + ;; + +aix[[4-9]]*) + version_type=linux + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test "$host_cpu" = ia64; then + # AIX 5 supports IA64 + library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line `#! .'. This would cause the generated library to + # depend on `.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[[01]] | aix4.[[01]].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # AIX (on Power*) has no versioning support, so currently we can not hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + if test "$aix_use_runtimelinking" = yes; then + # If using run time linking (on AIX 4.2 or later) use lib.so + # instead of lib.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + else + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='${libname}${release}.a $libname.a' + soname_spec='${libname}${release}${shared_ext}$major' + fi + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' + ;; + +beos*) + library_names_spec='${libname}${shared_ext}' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi[[45]]*) + version_type=linux + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32*) + version_type=windows + shrext_cmds=".dll" + need_version=no + need_lib_prefix=no + + case $GCC,$host_os in + yes,cygwin* | yes,mingw* | yes,pw32*) + library_names_spec='$libname.dll.a' + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i;echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $rm \$dlpath' + shlibpath_overrides_runpath=yes + + case $host_os in + cygwin*) + # Cygwin DLLs use 'cyg' prefix rather than 'lib' + soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib" + ;; + mingw*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if echo "$sys_lib_search_path_spec" | [grep ';[c-zC-Z]:/' >/dev/null]; then + # It is most probably a Windows format PATH printed by + # mingw gcc, but we are running on Cygwin. Gcc prints its search + # path with ; separators, and with drive letters. We can handle the + # drive letters (cygwin fileutils understands them), so leave them, + # especially as we might pass files found there to a mingw objdump, + # which wouldn't understand a cygwinified path. Ahh. + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + ;; + pw32*) + # pw32 DLLs use 'pw' prefix rather than 'lib' + library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + ;; + esac + ;; + + *) + library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib' + ;; + esac + dynamic_linker='Win32 ld.exe' + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${versuffix}$shared_ext ${libname}${release}${major}$shared_ext ${libname}$shared_ext' + soname_spec='${libname}${release}${major}$shared_ext' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' + m4_if([$1], [],[ + sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"]) + sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd1*) + dynamic_linker=no + ;; + +freebsd* | dragonfly*) + # DragonFly does not have aout. When/if they implement a new + # versioning mechanism, adjust this. + if test -x /usr/bin/objformat; then + objformat=`/usr/bin/objformat` + else + case $host_os in + freebsd[[123]]*) objformat=aout ;; + *) objformat=elf ;; + esac + fi + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[[01]]* | freebsdelf3.[[01]]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \ + freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1) + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + *) # from 4.6 on, and DragonFly + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + esac + ;; + +gnu*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + case $host_cpu in + ia64*) + shrext_cmds='.so' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + if test "X$HPUX_IA64_MODE" = X32; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + fi + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + hppa*64*) + shrext_cmds='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) + shrext_cmds='.sl' + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + ;; + esac + # HP-UX runs *really* slowly unless shared libraries are mode 555. + postinstall_cmds='chmod 555 $lib' + ;; + +interix[[3-9]]*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) + if test "$lt_cv_prog_gnu_ld" = yes; then + version_type=linux + else + version_type=irix + fi ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") + libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") + libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") + libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" + sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" + hardcode_into_libs=yes + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +# This must be Linux ELF. +linux* | k*bsd*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # Append ld.so.conf contents to the search path + if test -f /etc/ld.so.conf; then + lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '` + sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" + fi + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +nto-qnx*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +openbsd*) + version_type=sunos + sys_lib_dlsearch_path_spec="/usr/lib" + need_lib_prefix=no + # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. + case $host_os in + openbsd3.3 | openbsd3.3.*) need_version=yes ;; + *) need_version=no ;; + esac + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + case $host_os in + openbsd2.[[89]] | openbsd2.[[89]].*) + shlibpath_overrides_runpath=no + ;; + *) + shlibpath_overrides_runpath=yes + ;; + esac + else + shlibpath_overrides_runpath=yes + fi + ;; + +os2*) + libname_spec='$name' + shrext_cmds=".dll" + need_lib_prefix=no + library_names_spec='$libname${shared_ext} $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + ;; + +rdos*) + dynamic_linker=no + ;; + +solaris*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + export_dynamic_flag_spec='${wl}-Blargedynsym' + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec ;then + version_type=linux + library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' + soname_spec='$libname${shared_ext}.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + version_type=freebsd-elf + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + if test "$with_gnu_ld" = yes; then + sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' + shlibpath_overrides_runpath=no + else + sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' + shlibpath_overrides_runpath=yes + case $host_os in + sco3.2v5*) + sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" + ;; + esac + fi + sys_lib_dlsearch_path_spec='/usr/lib' + ;; + +uts4*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +AC_MSG_RESULT([$dynamic_linker]) +test "$dynamic_linker" = no && can_build_shared=no + +AC_CACHE_VAL([lt_cv_sys_lib_search_path_spec], +[lt_cv_sys_lib_search_path_spec="$sys_lib_search_path_spec"]) +sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" +AC_CACHE_VAL([lt_cv_sys_lib_dlsearch_path_spec], +[lt_cv_sys_lib_dlsearch_path_spec="$sys_lib_dlsearch_path_spec"]) +sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test "$GCC" = yes; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi +])# AC_LIBTOOL_SYS_DYNAMIC_LINKER + + +# _LT_AC_TAGCONFIG +# ---------------- +AC_DEFUN([_LT_AC_TAGCONFIG], +[AC_REQUIRE([LT_AC_PROG_SED])dnl +AC_ARG_WITH([tags], + [AC_HELP_STRING([--with-tags@<:@=TAGS@:>@], + [include additional configurations @<:@automatic@:>@])], + [tagnames="$withval"]) + +if test -f "$ltmain" && test -n "$tagnames"; then + if test ! -f "${ofile}"; then + AC_MSG_WARN([output file `$ofile' does not exist]) + fi + + if test -z "$LTCC"; then + eval "`$SHELL ${ofile} --config | grep '^LTCC='`" + if test -z "$LTCC"; then + AC_MSG_WARN([output file `$ofile' does not look like a libtool script]) + else + AC_MSG_WARN([using `LTCC=$LTCC', extracted from `$ofile']) + fi + fi + if test -z "$LTCFLAGS"; then + eval "`$SHELL ${ofile} --config | grep '^LTCFLAGS='`" + fi + + # Extract list of available tagged configurations in $ofile. + # Note that this assumes the entire list is on one line. + available_tags=`grep "^available_tags=" "${ofile}" | $SED -e 's/available_tags=\(.*$\)/\1/' -e 's/\"//g'` + + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for tagname in $tagnames; do + IFS="$lt_save_ifs" + # Check whether tagname contains only valid characters + case `$echo "X$tagname" | $Xsed -e 's:[[-_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890,/]]::g'` in + "") ;; + *) AC_MSG_ERROR([invalid tag name: $tagname]) + ;; + esac + + if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$" < "${ofile}" > /dev/null + then + AC_MSG_ERROR([tag name \"$tagname\" already exists]) + fi + + # Update the list of available tags. + if test -n "$tagname"; then + echo appending configuration tag \"$tagname\" to $ofile + + case $tagname in + CXX) + if test -n "$CXX" && ( test "X$CXX" != "Xno" && + ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || + (test "X$CXX" != "Xg++"))) ; then + AC_LIBTOOL_LANG_CXX_CONFIG + else + tagname="" + fi + ;; + + F77) + if test -n "$F77" && test "X$F77" != "Xno"; then + AC_LIBTOOL_LANG_F77_CONFIG + else + tagname="" + fi + ;; + + GCJ) + if test -n "$GCJ" && test "X$GCJ" != "Xno"; then + AC_LIBTOOL_LANG_GCJ_CONFIG + else + tagname="" + fi + ;; + + RC) + AC_LIBTOOL_LANG_RC_CONFIG + ;; + + *) + AC_MSG_ERROR([Unsupported tag name: $tagname]) + ;; + esac + + # Append the new tag name to the list of available tags. + if test -n "$tagname" ; then + available_tags="$available_tags $tagname" + fi + fi + done + IFS="$lt_save_ifs" + + # Now substitute the updated list of available tags. + if eval "sed -e 's/^available_tags=.*\$/available_tags=\"$available_tags\"/' \"$ofile\" > \"${ofile}T\""; then + mv "${ofile}T" "$ofile" + chmod +x "$ofile" + else + rm -f "${ofile}T" + AC_MSG_ERROR([unable to update list of available tagged configurations.]) + fi +fi +])# _LT_AC_TAGCONFIG + + +# AC_LIBTOOL_DLOPEN +# ----------------- +# enable checks for dlopen support +AC_DEFUN([AC_LIBTOOL_DLOPEN], + [AC_BEFORE([$0],[AC_LIBTOOL_SETUP]) +])# AC_LIBTOOL_DLOPEN + + +# AC_LIBTOOL_WIN32_DLL +# -------------------- +# declare package support for building win32 DLLs +AC_DEFUN([AC_LIBTOOL_WIN32_DLL], +[AC_BEFORE([$0], [AC_LIBTOOL_SETUP]) +])# AC_LIBTOOL_WIN32_DLL + + +# AC_ENABLE_SHARED([DEFAULT]) +# --------------------------- +# implement the --enable-shared flag +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +AC_DEFUN([AC_ENABLE_SHARED], +[define([AC_ENABLE_SHARED_DEFAULT], ifelse($1, no, no, yes))dnl +AC_ARG_ENABLE([shared], + [AC_HELP_STRING([--enable-shared@<:@=PKGS@:>@], + [build shared libraries @<:@default=]AC_ENABLE_SHARED_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_shared=yes ;; + no) enable_shared=no ;; + *) + enable_shared=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_shared=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_shared=]AC_ENABLE_SHARED_DEFAULT) +])# AC_ENABLE_SHARED + + +# AC_DISABLE_SHARED +# ----------------- +# set the default shared flag to --disable-shared +AC_DEFUN([AC_DISABLE_SHARED], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +AC_ENABLE_SHARED(no) +])# AC_DISABLE_SHARED + + +# AC_ENABLE_STATIC([DEFAULT]) +# --------------------------- +# implement the --enable-static flag +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +AC_DEFUN([AC_ENABLE_STATIC], +[define([AC_ENABLE_STATIC_DEFAULT], ifelse($1, no, no, yes))dnl +AC_ARG_ENABLE([static], + [AC_HELP_STRING([--enable-static@<:@=PKGS@:>@], + [build static libraries @<:@default=]AC_ENABLE_STATIC_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_static=yes ;; + no) enable_static=no ;; + *) + enable_static=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_static=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_static=]AC_ENABLE_STATIC_DEFAULT) +])# AC_ENABLE_STATIC + + +# AC_DISABLE_STATIC +# ----------------- +# set the default static flag to --disable-static +AC_DEFUN([AC_DISABLE_STATIC], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +AC_ENABLE_STATIC(no) +])# AC_DISABLE_STATIC + + +# AC_ENABLE_FAST_INSTALL([DEFAULT]) +# --------------------------------- +# implement the --enable-fast-install flag +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +AC_DEFUN([AC_ENABLE_FAST_INSTALL], +[define([AC_ENABLE_FAST_INSTALL_DEFAULT], ifelse($1, no, no, yes))dnl +AC_ARG_ENABLE([fast-install], + [AC_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@], + [optimize for fast installation @<:@default=]AC_ENABLE_FAST_INSTALL_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_fast_install=yes ;; + no) enable_fast_install=no ;; + *) + enable_fast_install=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_fast_install=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_fast_install=]AC_ENABLE_FAST_INSTALL_DEFAULT) +])# AC_ENABLE_FAST_INSTALL + + +# AC_DISABLE_FAST_INSTALL +# ----------------------- +# set the default to --disable-fast-install +AC_DEFUN([AC_DISABLE_FAST_INSTALL], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +AC_ENABLE_FAST_INSTALL(no) +])# AC_DISABLE_FAST_INSTALL + + +# AC_LIBTOOL_PICMODE([MODE]) +# -------------------------- +# implement the --with-pic flag +# MODE is either `yes' or `no'. If omitted, it defaults to `both'. +AC_DEFUN([AC_LIBTOOL_PICMODE], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +pic_mode=ifelse($#,1,$1,default) +])# AC_LIBTOOL_PICMODE + + +# AC_PROG_EGREP +# ------------- +# This is predefined starting with Autoconf 2.54, so this conditional +# definition can be removed once we require Autoconf 2.54 or later. +m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP], +[AC_CACHE_CHECK([for egrep], [ac_cv_prog_egrep], + [if echo a | (grep -E '(a|b)') >/dev/null 2>&1 + then ac_cv_prog_egrep='grep -E' + else ac_cv_prog_egrep='egrep' + fi]) + EGREP=$ac_cv_prog_egrep + AC_SUBST([EGREP]) +])]) + + +# AC_PATH_TOOL_PREFIX +# ------------------- +# find a file program which can recognize shared library +AC_DEFUN([AC_PATH_TOOL_PREFIX], +[AC_REQUIRE([AC_PROG_EGREP])dnl +AC_MSG_CHECKING([for $1]) +AC_CACHE_VAL(lt_cv_path_MAGIC_CMD, +[case $MAGIC_CMD in +[[\\/*] | ?:[\\/]*]) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; +*) + lt_save_MAGIC_CMD="$MAGIC_CMD" + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR +dnl $ac_dummy forces splitting on constant user-supplied paths. +dnl POSIX.2 word splitting is done only on the output of word expansions, +dnl not every word. This closes a longstanding sh security hole. + ac_dummy="ifelse([$2], , $PATH, [$2])" + for ac_dir in $ac_dummy; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$1; then + lt_cv_path_MAGIC_CMD="$ac_dir/$1" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + $EGREP "$file_magic_regex" > /dev/null; then + : + else + cat <&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +EOF + fi ;; + esac + fi + break + fi + done + IFS="$lt_save_ifs" + MAGIC_CMD="$lt_save_MAGIC_CMD" + ;; +esac]) +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + AC_MSG_RESULT($MAGIC_CMD) +else + AC_MSG_RESULT(no) +fi +])# AC_PATH_TOOL_PREFIX + + +# AC_PATH_MAGIC +# ------------- +# find a file program which can recognize a shared library +AC_DEFUN([AC_PATH_MAGIC], +[AC_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH) +if test -z "$lt_cv_path_MAGIC_CMD"; then + if test -n "$ac_tool_prefix"; then + AC_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH) + else + MAGIC_CMD=: + fi +fi +])# AC_PATH_MAGIC + + +# AC_PROG_LD +# ---------- +# find the pathname to the GNU or non-GNU linker +AC_DEFUN([AC_PROG_LD], +[AC_ARG_WITH([gnu-ld], + [AC_HELP_STRING([--with-gnu-ld], + [assume the C compiler uses GNU ld @<:@default=no@:>@])], + [test "$withval" = no || with_gnu_ld=yes], + [with_gnu_ld=no]) +AC_REQUIRE([LT_AC_PROG_SED])dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + AC_MSG_CHECKING([for ld used by $CC]) + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [[\\/]]* | ?:[[\\/]]*) + re_direlt='/[[^/]][[^/]]*/\.\./' + # Canonicalize the pathname of ld + ac_prog=`echo $ac_prog| $SED 's%\\\\%/%g'` + while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do + ac_prog=`echo $ac_prog| $SED "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + AC_MSG_CHECKING([for GNU ld]) +else + AC_MSG_CHECKING([for non-GNU ld]) +fi +AC_CACHE_VAL(lt_cv_path_LD, +[if test -z "$LD"; then + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some variants of GNU ld only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$lt_cv_path_LD" -v 2>&1 &1 /dev/null 2>&1; then + lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' + lt_cv_file_magic_cmd='func_win32_libid' + else + lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?' + lt_cv_file_magic_cmd='$OBJDUMP -f' + fi + ;; + +darwin* | rhapsody*) + lt_cv_deplibs_check_method=pass_all + ;; + +freebsd* | dragonfly*) + if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then + case $host_cpu in + i*86 ) + # Not sure whether the presence of OpenBSD here was a mistake. + # Let's accept both of them until this is cleared up. + lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` + ;; + esac + else + lt_cv_deplibs_check_method=pass_all + fi + ;; + +gnu*) + lt_cv_deplibs_check_method=pass_all + ;; + +hpux10.20* | hpux11*) + lt_cv_file_magic_cmd=/usr/bin/file + case $host_cpu in + ia64*) + lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64' + lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so + ;; + hppa*64*) + [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - PA-RISC [0-9].[0-9]'] + lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl + ;; + *) + lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]].[[0-9]]) shared library' + lt_cv_file_magic_test_file=/usr/lib/libc.sl + ;; + esac + ;; + +interix[[3-9]]*) + # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$' + ;; + +irix5* | irix6* | nonstopux*) + case $LD in + *-32|*"-32 ") libmagic=32-bit;; + *-n32|*"-n32 ") libmagic=N32;; + *-64|*"-64 ") libmagic=64-bit;; + *) libmagic=never-match;; + esac + lt_cv_deplibs_check_method=pass_all + ;; + +# This must be Linux ELF. +linux* | k*bsd*-gnu) + lt_cv_deplibs_check_method=pass_all + ;; + +netbsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$' + fi + ;; + +newos6*) + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=/usr/lib/libnls.so + ;; + +nto-qnx*) + lt_cv_deplibs_check_method=unknown + ;; + +openbsd*) + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' + fi + ;; + +osf3* | osf4* | osf5*) + lt_cv_deplibs_check_method=pass_all + ;; + +rdos*) + lt_cv_deplibs_check_method=pass_all + ;; + +solaris*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv4 | sysv4.3*) + case $host_vendor in + motorola) + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]' + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` + ;; + ncr) + lt_cv_deplibs_check_method=pass_all + ;; + sequent) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )' + ;; + sni) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib" + lt_cv_file_magic_test_file=/lib/libc.so + ;; + siemens) + lt_cv_deplibs_check_method=pass_all + ;; + pc) + lt_cv_deplibs_check_method=pass_all + ;; + esac + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + lt_cv_deplibs_check_method=pass_all + ;; +esac +]) +file_magic_cmd=$lt_cv_file_magic_cmd +deplibs_check_method=$lt_cv_deplibs_check_method +test -z "$deplibs_check_method" && deplibs_check_method=unknown +])# AC_DEPLIBS_CHECK_METHOD + + +# AC_PROG_NM +# ---------- +# find the pathname to a BSD-compatible name lister +AC_DEFUN([AC_PROG_NM], +[AC_CACHE_CHECK([for BSD-compatible nm], lt_cv_path_NM, +[if test -n "$NM"; then + # Let the user override the test. + lt_cv_path_NM="$NM" +else + lt_nm_to_check="${ac_tool_prefix}nm" + if test -n "$ac_tool_prefix" && test "$build" = "$host"; then + lt_nm_to_check="$lt_nm_to_check nm" + fi + for lt_tmp_nm in $lt_nm_to_check; do + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + tmp_nm="$ac_dir/$lt_tmp_nm" + if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then + # Check to see if the nm accepts a BSD-compat flag. + # Adding the `sed 1q' prevents false positives on HP-UX, which says: + # nm: unknown option "B" ignored + # Tru64's nm complains that /dev/null is an invalid object file + case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in + */dev/null* | *'Invalid file or object type'*) + lt_cv_path_NM="$tmp_nm -B" + break + ;; + *) + case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in + */dev/null*) + lt_cv_path_NM="$tmp_nm -p" + break + ;; + *) + lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but + continue # so that we can try to find one that supports BSD flags + ;; + esac + ;; + esac + fi + done + IFS="$lt_save_ifs" + done + test -z "$lt_cv_path_NM" && lt_cv_path_NM=nm +fi]) +NM="$lt_cv_path_NM" +])# AC_PROG_NM + + +# AC_CHECK_LIBM +# ------------- +# check for math library +AC_DEFUN([AC_CHECK_LIBM], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +LIBM= +case $host in +*-*-beos* | *-*-cygwin* | *-*-pw32* | *-*-darwin*) + # These system don't have libm, or don't need it + ;; +*-ncr-sysv4.3*) + AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw") + AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm") + ;; +*) + AC_CHECK_LIB(m, cos, LIBM="-lm") + ;; +esac +])# AC_CHECK_LIBM + + +# AC_LIBLTDL_CONVENIENCE([DIRECTORY]) +# ----------------------------------- +# sets LIBLTDL to the link flags for the libltdl convenience library and +# LTDLINCL to the include flags for the libltdl header and adds +# --enable-ltdl-convenience to the configure arguments. Note that +# AC_CONFIG_SUBDIRS is not called here. If DIRECTORY is not provided, +# it is assumed to be `libltdl'. LIBLTDL will be prefixed with +# '${top_builddir}/' and LTDLINCL will be prefixed with '${top_srcdir}/' +# (note the single quotes!). If your package is not flat and you're not +# using automake, define top_builddir and top_srcdir appropriately in +# the Makefiles. +AC_DEFUN([AC_LIBLTDL_CONVENIENCE], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl + case $enable_ltdl_convenience in + no) AC_MSG_ERROR([this package needs a convenience libltdl]) ;; + "") enable_ltdl_convenience=yes + ac_configure_args="$ac_configure_args --enable-ltdl-convenience" ;; + esac + LIBLTDL='${top_builddir}/'ifelse($#,1,[$1],['libltdl'])/libltdlc.la + LTDLINCL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl']) + # For backwards non-gettext consistent compatibility... + INCLTDL="$LTDLINCL" +])# AC_LIBLTDL_CONVENIENCE + + +# AC_LIBLTDL_INSTALLABLE([DIRECTORY]) +# ----------------------------------- +# sets LIBLTDL to the link flags for the libltdl installable library and +# LTDLINCL to the include flags for the libltdl header and adds +# --enable-ltdl-install to the configure arguments. Note that +# AC_CONFIG_SUBDIRS is not called here. If DIRECTORY is not provided, +# and an installed libltdl is not found, it is assumed to be `libltdl'. +# LIBLTDL will be prefixed with '${top_builddir}/'# and LTDLINCL with +# '${top_srcdir}/' (note the single quotes!). If your package is not +# flat and you're not using automake, define top_builddir and top_srcdir +# appropriately in the Makefiles. +# In the future, this macro may have to be called after AC_PROG_LIBTOOL. +AC_DEFUN([AC_LIBLTDL_INSTALLABLE], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl + AC_CHECK_LIB(ltdl, lt_dlinit, + [test x"$enable_ltdl_install" != xyes && enable_ltdl_install=no], + [if test x"$enable_ltdl_install" = xno; then + AC_MSG_WARN([libltdl not installed, but installation disabled]) + else + enable_ltdl_install=yes + fi + ]) + if test x"$enable_ltdl_install" = x"yes"; then + ac_configure_args="$ac_configure_args --enable-ltdl-install" + LIBLTDL='${top_builddir}/'ifelse($#,1,[$1],['libltdl'])/libltdl.la + LTDLINCL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl']) + else + ac_configure_args="$ac_configure_args --enable-ltdl-install=no" + LIBLTDL="-lltdl" + LTDLINCL= + fi + # For backwards non-gettext consistent compatibility... + INCLTDL="$LTDLINCL" +])# AC_LIBLTDL_INSTALLABLE + + +# AC_LIBTOOL_CXX +# -------------- +# enable support for C++ libraries +AC_DEFUN([AC_LIBTOOL_CXX], +[AC_REQUIRE([_LT_AC_LANG_CXX]) +])# AC_LIBTOOL_CXX + + +# _LT_AC_LANG_CXX +# --------------- +AC_DEFUN([_LT_AC_LANG_CXX], +[AC_REQUIRE([AC_PROG_CXX]) +AC_REQUIRE([_LT_AC_PROG_CXXCPP]) +_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}CXX]) +])# _LT_AC_LANG_CXX + +# _LT_AC_PROG_CXXCPP +# ------------------ +AC_DEFUN([_LT_AC_PROG_CXXCPP], +[ +AC_REQUIRE([AC_PROG_CXX]) +if test -n "$CXX" && ( test "X$CXX" != "Xno" && + ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || + (test "X$CXX" != "Xg++"))) ; then + AC_PROG_CXXCPP +fi +])# _LT_AC_PROG_CXXCPP + +# AC_LIBTOOL_F77 +# -------------- +# enable support for Fortran 77 libraries +AC_DEFUN([AC_LIBTOOL_F77], +[AC_REQUIRE([_LT_AC_LANG_F77]) +])# AC_LIBTOOL_F77 + + +# _LT_AC_LANG_F77 +# --------------- +AC_DEFUN([_LT_AC_LANG_F77], +[AC_REQUIRE([AC_PROG_F77]) +_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}F77]) +])# _LT_AC_LANG_F77 + + +# AC_LIBTOOL_GCJ +# -------------- +# enable support for GCJ libraries +AC_DEFUN([AC_LIBTOOL_GCJ], +[AC_REQUIRE([_LT_AC_LANG_GCJ]) +])# AC_LIBTOOL_GCJ + + +# _LT_AC_LANG_GCJ +# --------------- +AC_DEFUN([_LT_AC_LANG_GCJ], +[AC_PROVIDE_IFELSE([AC_PROG_GCJ],[], + [AC_PROVIDE_IFELSE([A][M_PROG_GCJ],[], + [AC_PROVIDE_IFELSE([LT_AC_PROG_GCJ],[], + [ifdef([AC_PROG_GCJ],[AC_REQUIRE([AC_PROG_GCJ])], + [ifdef([A][M_PROG_GCJ],[AC_REQUIRE([A][M_PROG_GCJ])], + [AC_REQUIRE([A][C_PROG_GCJ_OR_A][M_PROG_GCJ])])])])])]) +_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}GCJ]) +])# _LT_AC_LANG_GCJ + + +# AC_LIBTOOL_RC +# ------------- +# enable support for Windows resource files +AC_DEFUN([AC_LIBTOOL_RC], +[AC_REQUIRE([LT_AC_PROG_RC]) +_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}RC]) +])# AC_LIBTOOL_RC + + +# AC_LIBTOOL_LANG_C_CONFIG +# ------------------------ +# Ensure that the configuration vars for the C compiler are +# suitably defined. Those variables are subsequently used by +# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'. +AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG], [_LT_AC_LANG_C_CONFIG]) +AC_DEFUN([_LT_AC_LANG_C_CONFIG], +[lt_save_CC="$CC" +AC_LANG_PUSH(C) + +# Source file extension for C test sources. +ac_ext=c + +# Object file extension for compiled C test sources. +objext=o +_LT_AC_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="int some_variable = 0;" + +# Code to be used in simple link tests +lt_simple_link_test_code='int main(){return(0);}' + +_LT_AC_SYS_COMPILER + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +AC_LIBTOOL_PROG_COMPILER_NO_RTTI($1) +AC_LIBTOOL_PROG_COMPILER_PIC($1) +AC_LIBTOOL_PROG_CC_C_O($1) +AC_LIBTOOL_SYS_HARD_LINK_LOCKS($1) +AC_LIBTOOL_PROG_LD_SHLIBS($1) +AC_LIBTOOL_SYS_DYNAMIC_LINKER($1) +AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1) +AC_LIBTOOL_SYS_LIB_STRIP +AC_LIBTOOL_DLOPEN_SELF + +# Report which library types will actually be built +AC_MSG_CHECKING([if libtool supports shared libraries]) +AC_MSG_RESULT([$can_build_shared]) + +AC_MSG_CHECKING([whether to build shared libraries]) +test "$can_build_shared" = "no" && enable_shared=no + +# On AIX, shared libraries and static libraries use the same namespace, and +# are all built from PIC. +case $host_os in +aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + +aix[[4-9]]*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; +esac +AC_MSG_RESULT([$enable_shared]) + +AC_MSG_CHECKING([whether to build static libraries]) +# Make sure either enable_shared or enable_static is yes. +test "$enable_shared" = yes || enable_static=yes +AC_MSG_RESULT([$enable_static]) + +AC_LIBTOOL_CONFIG($1) + +AC_LANG_POP +CC="$lt_save_CC" +])# AC_LIBTOOL_LANG_C_CONFIG + + +# AC_LIBTOOL_LANG_CXX_CONFIG +# -------------------------- +# Ensure that the configuration vars for the C compiler are +# suitably defined. Those variables are subsequently used by +# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'. +AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG], [_LT_AC_LANG_CXX_CONFIG(CXX)]) +AC_DEFUN([_LT_AC_LANG_CXX_CONFIG], +[AC_LANG_PUSH(C++) +AC_REQUIRE([AC_PROG_CXX]) +AC_REQUIRE([_LT_AC_PROG_CXXCPP]) + +_LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no +_LT_AC_TAGVAR(allow_undefined_flag, $1)= +_LT_AC_TAGVAR(always_export_symbols, $1)=no +_LT_AC_TAGVAR(archive_expsym_cmds, $1)= +_LT_AC_TAGVAR(export_dynamic_flag_spec, $1)= +_LT_AC_TAGVAR(hardcode_direct, $1)=no +_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)= +_LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= +_LT_AC_TAGVAR(hardcode_libdir_separator, $1)= +_LT_AC_TAGVAR(hardcode_minus_L, $1)=no +_LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported +_LT_AC_TAGVAR(hardcode_automatic, $1)=no +_LT_AC_TAGVAR(module_cmds, $1)= +_LT_AC_TAGVAR(module_expsym_cmds, $1)= +_LT_AC_TAGVAR(link_all_deplibs, $1)=unknown +_LT_AC_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_AC_TAGVAR(no_undefined_flag, $1)= +_LT_AC_TAGVAR(whole_archive_flag_spec, $1)= +_LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=no + +# Dependencies to place before and after the object being linked: +_LT_AC_TAGVAR(predep_objects, $1)= +_LT_AC_TAGVAR(postdep_objects, $1)= +_LT_AC_TAGVAR(predeps, $1)= +_LT_AC_TAGVAR(postdeps, $1)= +_LT_AC_TAGVAR(compiler_lib_search_path, $1)= +_LT_AC_TAGVAR(compiler_lib_search_dirs, $1)= + +# Source file extension for C++ test sources. +ac_ext=cpp + +# Object file extension for compiled C++ test sources. +objext=o +_LT_AC_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="int some_variable = 0;" + +# Code to be used in simple link tests +lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }' + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. +_LT_AC_SYS_COMPILER + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +# Allow CC to be a program name with arguments. +lt_save_CC=$CC +lt_save_LD=$LD +lt_save_GCC=$GCC +GCC=$GXX +lt_save_with_gnu_ld=$with_gnu_ld +lt_save_path_LD=$lt_cv_path_LD +if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then + lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx +else + $as_unset lt_cv_prog_gnu_ld +fi +if test -n "${lt_cv_path_LDCXX+set}"; then + lt_cv_path_LD=$lt_cv_path_LDCXX +else + $as_unset lt_cv_path_LD +fi +test -z "${LDCXX+set}" || LD=$LDCXX +CC=${CXX-"c++"} +compiler=$CC +_LT_AC_TAGVAR(compiler, $1)=$CC +_LT_CC_BASENAME([$compiler]) + +# We don't want -fno-exception wen compiling C++ code, so set the +# no_builtin_flag separately +if test "$GXX" = yes; then + _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' +else + _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= +fi + +if test "$GXX" = yes; then + # Set up default GNU C++ configuration + + AC_PROG_LD + + # Check if GNU C++ uses GNU ld as the underlying linker, since the + # archiving commands below assume that GNU ld is being used. + if test "$with_gnu_ld" = yes; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + + # If archive_cmds runs LD, not CC, wlarc should be empty + # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to + # investigate it a little bit more. (MM) + wlarc='${wl}' + + # ancient GNU ld didn't support --whole-archive et. al. + if eval "`$CC -print-prog-name=ld` --help 2>&1" | \ + grep 'no-whole-archive' > /dev/null; then + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)= + fi + else + with_gnu_ld=no + wlarc= + + # A generic and very simple default shared library creation + # command for GNU C++ for the case where it uses the native + # linker, instead of GNU ld. If possible, this setting should + # overridden to take advantage of the native linker features on + # the platform it is being used on. + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + fi + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"' + +else + GXX=no + with_gnu_ld=no + wlarc= +fi + +# PORTME: fill in a description of your system's C++ link characteristics +AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) +_LT_AC_TAGVAR(ld_shlibs, $1)=yes +case $host_os in + aix3*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + aix[[4-9]]*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) + for ld_flag in $LDFLAGS; do + case $ld_flag in + *-brtl*) + aix_use_runtimelinking=yes + break + ;; + esac + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + _LT_AC_TAGVAR(archive_cmds, $1)='' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + + if test "$GXX" = yes; then + case $host_os in aix4.[[012]]|aix4.[[012]].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && \ + strings "$collect2name" | grep resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + _LT_AC_TAGVAR(hardcode_direct, $1)=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)= + fi + ;; + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to export. + _LT_AC_TAGVAR(always_export_symbols, $1)=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + _LT_AC_TAGVAR(allow_undefined_flag, $1)='-berok' + # Determine the default libpath from the value encoded in an empty executable. + _LT_AC_SYS_LIBPATH_AIX + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' + _LT_AC_TAGVAR(allow_undefined_flag, $1)="-z nodefs" + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an empty executable. + _LT_AC_SYS_LIBPATH_AIX + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + _LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' + # Exported symbols can be pulled into shared objects from archives + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='$convenience' + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes + # This is similar to how AIX traditionally builds its shared libraries. + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + beos*) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + chorus*) + case $cc_basename in + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + cygwin* | mingw* | pw32*) + # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, + # as there is no search path for DLLs. + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_AC_TAGVAR(always_export_symbols, $1)=no + _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + + if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + darwin* | rhapsody*) + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_automatic, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='' + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + _LT_AC_TAGVAR(allow_undefined_flag, $1)="$_lt_dar_allow_undefined" + if test "$GXX" = yes ; then + output_verbose_link_cmd='echo' + _LT_AC_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" + _LT_AC_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" + _LT_AC_TAGVAR(module_expsym_cmds, $1)="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" + if test "$lt_cv_apple_cc_single_mod" != "yes"; then + _LT_AC_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}" + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}" + fi + else + case $cc_basename in + xlc*) + output_verbose_link_cmd='echo' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj ${wl}-single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}`echo $rpath/$soname` $xlcverstring' + _LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' + # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -qmkshrobj ${wl}-single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}$rpath/$soname $xlcverstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + ;; + *) + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + fi + ;; + + dgux*) + case $cc_basename in + ec++*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + ghcx*) + # Green Hills C++ Compiler + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + freebsd[[12]]*) + # C++ shared libraries reported to be fairly broken before switch to ELF + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + freebsd-elf*) + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + ;; + freebsd* | dragonfly*) + # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF + # conventions + _LT_AC_TAGVAR(ld_shlibs, $1)=yes + ;; + gnu*) + ;; + hpux9*) + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, + # but as the default + # location of the library. + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + aCC*) + _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | grep "[[-]]L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + *) + if test "$GXX" = yes; then + _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -shared -nostdlib -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + hpux10*|hpux11*) + if test $with_gnu_ld = no; then + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + case $host_cpu in + hppa*64*|ia64*) ;; + *) + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + ;; + esac + fi + case $host_cpu in + hppa*64*|ia64*) + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + *) + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, + # but as the default + # location of the library. + ;; + esac + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + aCC*) + case $host_cpu in + hppa*64*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | grep "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + *) + if test "$GXX" = yes; then + if test $with_gnu_ld = no; then + case $host_cpu in + hppa*64*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + fi + else + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + interix[[3-9]]*) + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + irix5* | irix6*) + case $cc_basename in + CC*) + # SGI C++ + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + + # Archives containing C++ object files must be created using + # "CC -ar", where "CC" is the IRIX C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs' + ;; + *) + if test "$GXX" = yes; then + if test "$with_gnu_ld" = no; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` -o $lib' + fi + fi + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + ;; + esac + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + linux* | k*bsd*-gnu) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + _LT_AC_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | grep "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath,$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + + # Archives containing C++ object files must be created using + # "CC -Bstatic", where "CC" is the KAI C++ compiler. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' + ;; + icpc*) + # Intel C++ + with_gnu_ld=yes + # version 8.0 and above of icpc choke on multiply defined symbols + # if we add $predep_objects and $postdep_objects, however 7.1 and + # earlier do not add the objects themselves. + case `$CC -V 2>&1` in + *"Version 7."*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + ;; + *) # Version 8.0 or newer + tmp_idyn= + case $host_cpu in + ia64*) tmp_idyn=' -i_dynamic';; + esac + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + ;; + esac + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + ;; + pgCC* | pgcpp*) + # Portland Group C++ compiler + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' + ;; + cxx*) + # Compaq C++ + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols' + + runpath_var=LD_RUN_PATH + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + _LT_AC_TAGVAR(no_undefined_flag, $1)=' -zdefs' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' + + # Not sure whether something based on + # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 + # would be better. + output_verbose_link_cmd='echo' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' + ;; + esac + ;; + esac + ;; + lynxos*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + m88k*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + mvs*) + case $cc_basename in + cxx*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + netbsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' + wlarc= + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + fi + # Workaround some broken pre-1.5 toolchains + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' + ;; + openbsd2*) + # C++ shared libraries are fairly broken + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + openbsd*) + if test -f /usr/libexec/ld.so; then + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + fi + output_verbose_link_cmd='echo' + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + osf3*) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + _LT_AC_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Archives containing C++ object files must be created using + # "CC -Bstatic", where "CC" is the KAI C++ compiler. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' + + ;; + RCC*) + # Rational C++ 2.4.1 + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + cxx*) + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && echo ${wl}-set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld" | grep -v "ld:"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + *) + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"' + + else + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + osf4* | osf5*) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + _LT_AC_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Archives containing C++ object files must be created using + # the KAI C++ compiler. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' + ;; + RCC*) + # Rational C++ 2.4.1 + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + cxx*) + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ + echo "-hidden">> $lib.exp~ + $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname -Wl,-input -Wl,$lib.exp `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib~ + $rm $lib.exp' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld" | grep -v "ld:"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + *) + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"' + + else + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + psos*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + lcc*) + # Lucid + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + solaris*) + case $cc_basename in + CC*) + # Sun C++ 4.2, 5.x and Centerline C++ + _LT_AC_TAGVAR(archive_cmds_need_lc,$1)=yes + _LT_AC_TAGVAR(no_undefined_flag, $1)=' -zdefs' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) + # The compiler driver will combine and reorder linker options, + # but understands `-z linker_flag'. + # Supported since Solaris 2.6 (maybe 2.5.1?) + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' + ;; + esac + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + + output_verbose_link_cmd='echo' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' + ;; + gcx*) + # Green Hills C++ Compiler + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + + # The C++ compiler must be used to create the archive. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs' + ;; + *) + # GNU C++ compiler with Solaris linker + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + _LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs' + if $CC --version | grep -v '^2\.7' > /dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -shared -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd="$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep \"\-L\"" + else + # g++ 2.7 appears to require `-G' NOT `-shared' on this + # platform. + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd="$CC -G $CFLAGS -v conftest.$objext 2>&1 | grep \"\-L\"" + fi + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir' + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' + ;; + esac + fi + ;; + esac + ;; + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) + _LT_AC_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + # For security reasons, it is highly recommended that you always + # use absolute paths for naming shared libraries, and exclude the + # DT_RUNPATH tag from executables and libraries. But doing so + # requires that you compile everything twice, which is a pain. + # So that behaviour is only enabled if SCOABSPATH is set to a + # non-empty value in the environment. Most likely only useful for + # creating official distributions of packages. + # This is a hack until libtool officially supports absolute path + # names for shared libraries. + _LT_AC_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs' + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + vxworks*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; +esac +AC_MSG_RESULT([$_LT_AC_TAGVAR(ld_shlibs, $1)]) +test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no + +_LT_AC_TAGVAR(GCC, $1)="$GXX" +_LT_AC_TAGVAR(LD, $1)="$LD" + +AC_LIBTOOL_POSTDEP_PREDEP($1) +AC_LIBTOOL_PROG_COMPILER_PIC($1) +AC_LIBTOOL_PROG_CC_C_O($1) +AC_LIBTOOL_SYS_HARD_LINK_LOCKS($1) +AC_LIBTOOL_PROG_LD_SHLIBS($1) +AC_LIBTOOL_SYS_DYNAMIC_LINKER($1) +AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1) + +AC_LIBTOOL_CONFIG($1) + +AC_LANG_POP +CC=$lt_save_CC +LDCXX=$LD +LD=$lt_save_LD +GCC=$lt_save_GCC +with_gnu_ldcxx=$with_gnu_ld +with_gnu_ld=$lt_save_with_gnu_ld +lt_cv_path_LDCXX=$lt_cv_path_LD +lt_cv_path_LD=$lt_save_path_LD +lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld +lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld +])# AC_LIBTOOL_LANG_CXX_CONFIG + +# AC_LIBTOOL_POSTDEP_PREDEP([TAGNAME]) +# ------------------------------------ +# Figure out "hidden" library dependencies from verbose +# compiler output when linking a shared library. +# Parse the compiler output and extract the necessary +# objects, libraries and library flags. +AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP], +[AC_REQUIRE([LT_AC_PROG_SED])dnl +dnl we can't use the lt_simple_compile_test_code here, +dnl because it contains code intended for an executable, +dnl not a library. It's possible we should let each +dnl tag define a new lt_????_link_test_code variable, +dnl but it's only used here... +ifelse([$1],[],[cat > conftest.$ac_ext < conftest.$ac_ext < conftest.$ac_ext < conftest.$ac_ext <&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + # + # The more standards-conforming stlport4 library is + # incompatible with the Cstd library. Avoid specifying + # it if it's in CXXFLAGS. Ignore libCrun as + # -library=stlport4 depends on it. + case " $CXX $CXXFLAGS " in + *" -library=stlport4 "*) + solaris_use_stlport4=yes + ;; + esac + if test "$solaris_use_stlport4" != yes; then + _LT_AC_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun' + fi + ;; + esac + ;; + +solaris*) + case $cc_basename in + CC*) + # The more standards-conforming stlport4 library is + # incompatible with the Cstd library. Avoid specifying + # it if it's in CXXFLAGS. Ignore libCrun as + # -library=stlport4 depends on it. + case " $CXX $CXXFLAGS " in + *" -library=stlport4 "*) + solaris_use_stlport4=yes + ;; + esac + + # Adding this requires a known-good setup of shared libraries for + # Sun compiler versions before 5.6, else PIC objects from an old + # archive will be linked into the output, leading to subtle bugs. + if test "$solaris_use_stlport4" != yes; then + _LT_AC_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun' + fi + ;; + esac + ;; +esac +]) +case " $_LT_AC_TAGVAR(postdeps, $1) " in +*" -lc "*) _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no ;; +esac +])# AC_LIBTOOL_POSTDEP_PREDEP + +# AC_LIBTOOL_LANG_F77_CONFIG +# -------------------------- +# Ensure that the configuration vars for the C compiler are +# suitably defined. Those variables are subsequently used by +# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'. +AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG], [_LT_AC_LANG_F77_CONFIG(F77)]) +AC_DEFUN([_LT_AC_LANG_F77_CONFIG], +[AC_REQUIRE([AC_PROG_F77]) +AC_LANG_PUSH(Fortran 77) + +_LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no +_LT_AC_TAGVAR(allow_undefined_flag, $1)= +_LT_AC_TAGVAR(always_export_symbols, $1)=no +_LT_AC_TAGVAR(archive_expsym_cmds, $1)= +_LT_AC_TAGVAR(export_dynamic_flag_spec, $1)= +_LT_AC_TAGVAR(hardcode_direct, $1)=no +_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)= +_LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= +_LT_AC_TAGVAR(hardcode_libdir_separator, $1)= +_LT_AC_TAGVAR(hardcode_minus_L, $1)=no +_LT_AC_TAGVAR(hardcode_automatic, $1)=no +_LT_AC_TAGVAR(module_cmds, $1)= +_LT_AC_TAGVAR(module_expsym_cmds, $1)= +_LT_AC_TAGVAR(link_all_deplibs, $1)=unknown +_LT_AC_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_AC_TAGVAR(no_undefined_flag, $1)= +_LT_AC_TAGVAR(whole_archive_flag_spec, $1)= +_LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=no + +# Source file extension for f77 test sources. +ac_ext=f + +# Object file extension for compiled f77 test sources. +objext=o +_LT_AC_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="\ + subroutine t + return + end +" + +# Code to be used in simple link tests +lt_simple_link_test_code="\ + program t + end +" + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. +_LT_AC_SYS_COMPILER + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +# Allow CC to be a program name with arguments. +lt_save_CC="$CC" +CC=${F77-"f77"} +compiler=$CC +_LT_AC_TAGVAR(compiler, $1)=$CC +_LT_CC_BASENAME([$compiler]) + +AC_MSG_CHECKING([if libtool supports shared libraries]) +AC_MSG_RESULT([$can_build_shared]) + +AC_MSG_CHECKING([whether to build shared libraries]) +test "$can_build_shared" = "no" && enable_shared=no + +# On AIX, shared libraries and static libraries use the same namespace, and +# are all built from PIC. +case $host_os in +aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; +aix[[4-9]]*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; +esac +AC_MSG_RESULT([$enable_shared]) + +AC_MSG_CHECKING([whether to build static libraries]) +# Make sure either enable_shared or enable_static is yes. +test "$enable_shared" = yes || enable_static=yes +AC_MSG_RESULT([$enable_static]) + +_LT_AC_TAGVAR(GCC, $1)="$G77" +_LT_AC_TAGVAR(LD, $1)="$LD" + +AC_LIBTOOL_PROG_COMPILER_PIC($1) +AC_LIBTOOL_PROG_CC_C_O($1) +AC_LIBTOOL_SYS_HARD_LINK_LOCKS($1) +AC_LIBTOOL_PROG_LD_SHLIBS($1) +AC_LIBTOOL_SYS_DYNAMIC_LINKER($1) +AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1) + +AC_LIBTOOL_CONFIG($1) + +AC_LANG_POP +CC="$lt_save_CC" +])# AC_LIBTOOL_LANG_F77_CONFIG + + +# AC_LIBTOOL_LANG_GCJ_CONFIG +# -------------------------- +# Ensure that the configuration vars for the C compiler are +# suitably defined. Those variables are subsequently used by +# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'. +AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG], [_LT_AC_LANG_GCJ_CONFIG(GCJ)]) +AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG], +[AC_LANG_SAVE + +# Source file extension for Java test sources. +ac_ext=java + +# Object file extension for compiled Java test sources. +objext=o +_LT_AC_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="class foo {}" + +# Code to be used in simple link tests +lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }' + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. +_LT_AC_SYS_COMPILER + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +# Allow CC to be a program name with arguments. +lt_save_CC="$CC" +CC=${GCJ-"gcj"} +compiler=$CC +_LT_AC_TAGVAR(compiler, $1)=$CC +_LT_CC_BASENAME([$compiler]) + +# GCJ did not exist at the time GCC didn't implicitly link libc in. +_LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + +_LT_AC_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds + +AC_LIBTOOL_PROG_COMPILER_NO_RTTI($1) +AC_LIBTOOL_PROG_COMPILER_PIC($1) +AC_LIBTOOL_PROG_CC_C_O($1) +AC_LIBTOOL_SYS_HARD_LINK_LOCKS($1) +AC_LIBTOOL_PROG_LD_SHLIBS($1) +AC_LIBTOOL_SYS_DYNAMIC_LINKER($1) +AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1) + +AC_LIBTOOL_CONFIG($1) + +AC_LANG_RESTORE +CC="$lt_save_CC" +])# AC_LIBTOOL_LANG_GCJ_CONFIG + + +# AC_LIBTOOL_LANG_RC_CONFIG +# ------------------------- +# Ensure that the configuration vars for the Windows resource compiler are +# suitably defined. Those variables are subsequently used by +# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'. +AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG], [_LT_AC_LANG_RC_CONFIG(RC)]) +AC_DEFUN([_LT_AC_LANG_RC_CONFIG], +[AC_LANG_SAVE + +# Source file extension for RC test sources. +ac_ext=rc + +# Object file extension for compiled RC test sources. +objext=o +_LT_AC_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }' + +# Code to be used in simple link tests +lt_simple_link_test_code="$lt_simple_compile_test_code" + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. +_LT_AC_SYS_COMPILER + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +# Allow CC to be a program name with arguments. +lt_save_CC="$CC" +CC=${RC-"windres"} +compiler=$CC +_LT_AC_TAGVAR(compiler, $1)=$CC +_LT_CC_BASENAME([$compiler]) +_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes + +AC_LIBTOOL_CONFIG($1) + +AC_LANG_RESTORE +CC="$lt_save_CC" +])# AC_LIBTOOL_LANG_RC_CONFIG + + +# AC_LIBTOOL_CONFIG([TAGNAME]) +# ---------------------------- +# If TAGNAME is not passed, then create an initial libtool script +# with a default configuration from the untagged config vars. Otherwise +# add code to config.status for appending the configuration named by +# TAGNAME from the matching tagged config vars. +AC_DEFUN([AC_LIBTOOL_CONFIG], +[# The else clause should only fire when bootstrapping the +# libtool distribution, otherwise you forgot to ship ltmain.sh +# with your package, and you will get complaints that there are +# no rules to generate ltmain.sh. +if test -f "$ltmain"; then + # See if we are running on zsh, and set the options which allow our commands through + # without removal of \ escapes. + if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST + fi + # Now quote all the things that may contain metacharacters while being + # careful not to overquote the AC_SUBSTed values. We take copies of the + # variables and quote the copies for generation of the libtool script. + for var in echo old_CC old_CFLAGS AR AR_FLAGS EGREP RANLIB LN_S LTCC LTCFLAGS NM \ + SED SHELL STRIP \ + libname_spec library_names_spec soname_spec extract_expsyms_cmds \ + old_striplib striplib file_magic_cmd finish_cmds finish_eval \ + deplibs_check_method reload_flag reload_cmds need_locks \ + lt_cv_sys_global_symbol_pipe lt_cv_sys_global_symbol_to_cdecl \ + lt_cv_sys_global_symbol_to_c_name_address \ + sys_lib_search_path_spec sys_lib_dlsearch_path_spec \ + old_postinstall_cmds old_postuninstall_cmds \ + _LT_AC_TAGVAR(compiler, $1) \ + _LT_AC_TAGVAR(CC, $1) \ + _LT_AC_TAGVAR(LD, $1) \ + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1) \ + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1) \ + _LT_AC_TAGVAR(lt_prog_compiler_static, $1) \ + _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) \ + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1) \ + _LT_AC_TAGVAR(thread_safe_flag_spec, $1) \ + _LT_AC_TAGVAR(whole_archive_flag_spec, $1) \ + _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1) \ + _LT_AC_TAGVAR(old_archive_cmds, $1) \ + _LT_AC_TAGVAR(old_archive_from_new_cmds, $1) \ + _LT_AC_TAGVAR(predep_objects, $1) \ + _LT_AC_TAGVAR(postdep_objects, $1) \ + _LT_AC_TAGVAR(predeps, $1) \ + _LT_AC_TAGVAR(postdeps, $1) \ + _LT_AC_TAGVAR(compiler_lib_search_path, $1) \ + _LT_AC_TAGVAR(compiler_lib_search_dirs, $1) \ + _LT_AC_TAGVAR(archive_cmds, $1) \ + _LT_AC_TAGVAR(archive_expsym_cmds, $1) \ + _LT_AC_TAGVAR(postinstall_cmds, $1) \ + _LT_AC_TAGVAR(postuninstall_cmds, $1) \ + _LT_AC_TAGVAR(old_archive_from_expsyms_cmds, $1) \ + _LT_AC_TAGVAR(allow_undefined_flag, $1) \ + _LT_AC_TAGVAR(no_undefined_flag, $1) \ + _LT_AC_TAGVAR(export_symbols_cmds, $1) \ + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) \ + _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1) \ + _LT_AC_TAGVAR(hardcode_libdir_separator, $1) \ + _LT_AC_TAGVAR(hardcode_automatic, $1) \ + _LT_AC_TAGVAR(module_cmds, $1) \ + _LT_AC_TAGVAR(module_expsym_cmds, $1) \ + _LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1) \ + _LT_AC_TAGVAR(fix_srcfile_path, $1) \ + _LT_AC_TAGVAR(exclude_expsyms, $1) \ + _LT_AC_TAGVAR(include_expsyms, $1); do + + case $var in + _LT_AC_TAGVAR(old_archive_cmds, $1) | \ + _LT_AC_TAGVAR(old_archive_from_new_cmds, $1) | \ + _LT_AC_TAGVAR(archive_cmds, $1) | \ + _LT_AC_TAGVAR(archive_expsym_cmds, $1) | \ + _LT_AC_TAGVAR(module_cmds, $1) | \ + _LT_AC_TAGVAR(module_expsym_cmds, $1) | \ + _LT_AC_TAGVAR(old_archive_from_expsyms_cmds, $1) | \ + _LT_AC_TAGVAR(export_symbols_cmds, $1) | \ + extract_expsyms_cmds | reload_cmds | finish_cmds | \ + postinstall_cmds | postuninstall_cmds | \ + old_postinstall_cmds | old_postuninstall_cmds | \ + sys_lib_search_path_spec | sys_lib_dlsearch_path_spec) + # Double-quote double-evaled strings. + eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\"" + ;; + *) + eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\"" + ;; + esac + done + + case $lt_echo in + *'\[$]0 --fallback-echo"') + lt_echo=`$echo "X$lt_echo" | $Xsed -e 's/\\\\\\\[$]0 --fallback-echo"[$]/[$]0 --fallback-echo"/'` + ;; + esac + +ifelse([$1], [], + [cfgfile="${ofile}T" + trap "$rm \"$cfgfile\"; exit 1" 1 2 15 + $rm -f "$cfgfile" + AC_MSG_NOTICE([creating $ofile])], + [cfgfile="$ofile"]) + + cat <<__EOF__ >> "$cfgfile" +ifelse([$1], [], +[#! $SHELL + +# `$echo "$cfgfile" | sed 's%^.*/%%'` - Provide generalized library-building support services. +# Generated automatically by $PROGRAM (GNU $PACKAGE $VERSION$TIMESTAMP) +# NOTE: Changes made to this file will be lost: look at ltmain.sh. +# +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 +# Free Software Foundation, Inc. +# +# This file is part of GNU Libtool: +# Originally by Gordon Matzigkeit , 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 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# 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. + +# A sed program that does not truncate output. +SED=$lt_SED + +# Sed that helps us avoid accidentally triggering echo(1) options like -n. +Xsed="$SED -e 1s/^X//" + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +# The names of the tagged configurations supported by this script. +available_tags= + +# ### BEGIN LIBTOOL CONFIG], +[# ### BEGIN LIBTOOL TAG CONFIG: $tagname]) + +# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: + +# Shell to use when invoking shell scripts. +SHELL=$lt_SHELL + +# Whether or not to build shared libraries. +build_libtool_libs=$enable_shared + +# Whether or not to build static libraries. +build_old_libs=$enable_static + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=$_LT_AC_TAGVAR(archive_cmds_need_lc, $1) + +# Whether or not to disallow shared libs when runtime libs are static +allow_libtool_libs_with_static_runtimes=$_LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1) + +# Whether or not to optimize for fast installation. +fast_install=$enable_fast_install + +# The host system. +host_alias=$host_alias +host=$host +host_os=$host_os + +# The build system. +build_alias=$build_alias +build=$build +build_os=$build_os + +# An echo program that does not interpret backslashes. +echo=$lt_echo + +# The archiver. +AR=$lt_AR +AR_FLAGS=$lt_AR_FLAGS + +# A C compiler. +LTCC=$lt_LTCC + +# LTCC compiler flags. +LTCFLAGS=$lt_LTCFLAGS + +# A language-specific compiler. +CC=$lt_[]_LT_AC_TAGVAR(compiler, $1) + +# Is the compiler the GNU C compiler? +with_gcc=$_LT_AC_TAGVAR(GCC, $1) + +# An ERE matcher. +EGREP=$lt_EGREP + +# The linker used to build libraries. +LD=$lt_[]_LT_AC_TAGVAR(LD, $1) + +# Whether we need hard or soft links. +LN_S=$lt_LN_S + +# A BSD-compatible nm program. +NM=$lt_NM + +# A symbol stripping program +STRIP=$lt_STRIP + +# Used to examine libraries when file_magic_cmd begins "file" +MAGIC_CMD=$MAGIC_CMD + +# Used on cygwin: DLL creation program. +DLLTOOL="$DLLTOOL" + +# Used on cygwin: object dumper. +OBJDUMP="$OBJDUMP" + +# Used on cygwin: assembler. +AS="$AS" + +# The name of the directory that contains temporary libtool files. +objdir=$objdir + +# How to create reloadable object files. +reload_flag=$lt_reload_flag +reload_cmds=$lt_reload_cmds + +# How to pass a linker flag through the compiler. +wl=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_wl, $1) + +# Object file suffix (normally "o"). +objext="$ac_objext" + +# Old archive suffix (normally "a"). +libext="$libext" + +# Shared library suffix (normally ".so"). +shrext_cmds='$shrext_cmds' + +# Executable file suffix (normally ""). +exeext="$exeext" + +# Additional compiler flags for building library objects. +pic_flag=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) +pic_mode=$pic_mode + +# What is the maximum length of a command? +max_cmd_len=$lt_cv_sys_max_cmd_len + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$lt_[]_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1) + +# Must we lock files when doing compilation? +need_locks=$lt_need_locks + +# Do we need the lib prefix for modules? +need_lib_prefix=$need_lib_prefix + +# Do we need a version for libraries? +need_version=$need_version + +# Whether dlopen is supported. +dlopen_support=$enable_dlopen + +# Whether dlopen of programs is supported. +dlopen_self=$enable_dlopen_self + +# Whether dlopen of statically linked programs is supported. +dlopen_self_static=$enable_dlopen_self_static + +# Compiler flag to prevent dynamic linking. +link_static_flag=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_static, $1) + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec=$lt_[]_LT_AC_TAGVAR(export_dynamic_flag_spec, $1) + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec=$lt_[]_LT_AC_TAGVAR(whole_archive_flag_spec, $1) + +# Compiler flag to generate thread-safe objects. +thread_safe_flag_spec=$lt_[]_LT_AC_TAGVAR(thread_safe_flag_spec, $1) + +# Library versioning type. +version_type=$version_type + +# Format of library name prefix. +libname_spec=$lt_libname_spec + +# List of archive names. First name is the real one, the rest are links. +# The last name is the one that the linker finds with -lNAME. +library_names_spec=$lt_library_names_spec + +# The coded name of the library, if different from the real name. +soname_spec=$lt_soname_spec + +# Commands used to build and install an old-style archive. +RANLIB=$lt_RANLIB +old_archive_cmds=$lt_[]_LT_AC_TAGVAR(old_archive_cmds, $1) +old_postinstall_cmds=$lt_old_postinstall_cmds +old_postuninstall_cmds=$lt_old_postuninstall_cmds + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds=$lt_[]_LT_AC_TAGVAR(old_archive_from_new_cmds, $1) + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds=$lt_[]_LT_AC_TAGVAR(old_archive_from_expsyms_cmds, $1) + +# Commands used to build and install a shared archive. +archive_cmds=$lt_[]_LT_AC_TAGVAR(archive_cmds, $1) +archive_expsym_cmds=$lt_[]_LT_AC_TAGVAR(archive_expsym_cmds, $1) +postinstall_cmds=$lt_postinstall_cmds +postuninstall_cmds=$lt_postuninstall_cmds + +# Commands used to build a loadable module (assumed same as above if empty) +module_cmds=$lt_[]_LT_AC_TAGVAR(module_cmds, $1) +module_expsym_cmds=$lt_[]_LT_AC_TAGVAR(module_expsym_cmds, $1) + +# Commands to strip libraries. +old_striplib=$lt_old_striplib +striplib=$lt_striplib + +# Dependencies to place before the objects being linked to create a +# shared library. +predep_objects=$lt_[]_LT_AC_TAGVAR(predep_objects, $1) + +# Dependencies to place after the objects being linked to create a +# shared library. +postdep_objects=$lt_[]_LT_AC_TAGVAR(postdep_objects, $1) + +# Dependencies to place before the objects being linked to create a +# shared library. +predeps=$lt_[]_LT_AC_TAGVAR(predeps, $1) + +# Dependencies to place after the objects being linked to create a +# shared library. +postdeps=$lt_[]_LT_AC_TAGVAR(postdeps, $1) + +# The directories searched by this compiler when creating a shared +# library +compiler_lib_search_dirs=$lt_[]_LT_AC_TAGVAR(compiler_lib_search_dirs, $1) + +# The library search path used internally by the compiler when linking +# a shared library. +compiler_lib_search_path=$lt_[]_LT_AC_TAGVAR(compiler_lib_search_path, $1) + +# Method to check whether dependent libraries are shared objects. +deplibs_check_method=$lt_deplibs_check_method + +# Command to use when deplibs_check_method == file_magic. +file_magic_cmd=$lt_file_magic_cmd + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$lt_[]_LT_AC_TAGVAR(allow_undefined_flag, $1) + +# Flag that forces no undefined symbols. +no_undefined_flag=$lt_[]_LT_AC_TAGVAR(no_undefined_flag, $1) + +# Commands used to finish a libtool library installation in a directory. +finish_cmds=$lt_finish_cmds + +# Same as above, but a single script fragment to be evaled but not shown. +finish_eval=$lt_finish_eval + +# Take the output of nm and produce a listing of raw symbols and C names. +global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe + +# Transform the output of nm in a proper C declaration +global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl + +# Transform the output of nm in a C name address pair +global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address + +# This is the shared library runtime path variable. +runpath_var=$runpath_var + +# This is the shared library path variable. +shlibpath_var=$shlibpath_var + +# Is shlibpath searched before the hard-coded library search path? +shlibpath_overrides_runpath=$shlibpath_overrides_runpath + +# How to hardcode a shared library path into an executable. +hardcode_action=$_LT_AC_TAGVAR(hardcode_action, $1) + +# Whether we should hardcode library paths into libraries. +hardcode_into_libs=$hardcode_into_libs + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist. +hardcode_libdir_flag_spec=$lt_[]_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) + +# If ld is used when linking, flag to hardcode \$libdir into +# a binary during linking. This must work even if \$libdir does +# not exist. +hardcode_libdir_flag_spec_ld=$lt_[]_LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1) + +# Whether we need a single -rpath flag with a separated argument. +hardcode_libdir_separator=$lt_[]_LT_AC_TAGVAR(hardcode_libdir_separator, $1) + +# Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the +# resulting binary. +hardcode_direct=$_LT_AC_TAGVAR(hardcode_direct, $1) + +# Set to yes if using the -LDIR flag during linking hardcodes DIR into the +# resulting binary. +hardcode_minus_L=$_LT_AC_TAGVAR(hardcode_minus_L, $1) + +# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into +# the resulting binary. +hardcode_shlibpath_var=$_LT_AC_TAGVAR(hardcode_shlibpath_var, $1) + +# Set to yes if building a shared library automatically hardcodes DIR into the library +# and all subsequent libraries and executables linked against it. +hardcode_automatic=$_LT_AC_TAGVAR(hardcode_automatic, $1) + +# Variables whose values should be saved in libtool wrapper scripts and +# restored at relink time. +variables_saved_for_relink="$variables_saved_for_relink" + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=$_LT_AC_TAGVAR(link_all_deplibs, $1) + +# Compile-time system search path for libraries +sys_lib_search_path_spec=$lt_sys_lib_search_path_spec + +# Run-time system search path for libraries +sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec + +# Fix the shell variable \$srcfile for the compiler. +fix_srcfile_path=$lt_fix_srcfile_path + +# Set to yes if exported symbols are required. +always_export_symbols=$_LT_AC_TAGVAR(always_export_symbols, $1) + +# The commands to list exported symbols. +export_symbols_cmds=$lt_[]_LT_AC_TAGVAR(export_symbols_cmds, $1) + +# The commands to extract the exported symbol list from a shared archive. +extract_expsyms_cmds=$lt_extract_expsyms_cmds + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms=$lt_[]_LT_AC_TAGVAR(exclude_expsyms, $1) + +# Symbols that must always be exported. +include_expsyms=$lt_[]_LT_AC_TAGVAR(include_expsyms, $1) + +ifelse([$1],[], +[# ### END LIBTOOL CONFIG], +[# ### END LIBTOOL TAG CONFIG: $tagname]) + +__EOF__ + +ifelse([$1],[], [ + case $host_os in + aix3*) + cat <<\EOF >> "$cfgfile" + +# AIX sometimes has problems with the GCC collect2 program. For some +# reason, if we set the COLLECT_NAMES environment variable, the problems +# vanish in a puff of smoke. +if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES +fi +EOF + ;; + esac + + # We use sed instead of cat because bash on DJGPP gets confused if + # if finds mixed CR/LF and LF-only lines. Since sed operates in + # text mode, it properly converts lines to CR/LF. This bash problem + # is reportedly fixed, but why not run on old versions too? + sed '$q' "$ltmain" >> "$cfgfile" || (rm -f "$cfgfile"; exit 1) + + mv -f "$cfgfile" "$ofile" || \ + (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") + chmod +x "$ofile" +]) +else + # If there is no Makefile yet, we rely on a make rule to execute + # `config.status --recheck' to rerun these tests and create the + # libtool script then. + ltmain_in=`echo $ltmain | sed -e 's/\.sh$/.in/'` + if test -f "$ltmain_in"; then + test -f Makefile && make "$ltmain" + fi +fi +])# AC_LIBTOOL_CONFIG + + +# AC_LIBTOOL_PROG_COMPILER_NO_RTTI([TAGNAME]) +# ------------------------------------------- +AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], +[AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl + +_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= + +if test "$GCC" = yes; then + _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' + + AC_LIBTOOL_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions], + lt_cv_prog_compiler_rtti_exceptions, + [-fno-rtti -fno-exceptions], [], + [_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"]) +fi +])# AC_LIBTOOL_PROG_COMPILER_NO_RTTI + + +# AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE +# --------------------------------- +AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], +[AC_REQUIRE([AC_CANONICAL_HOST]) +AC_REQUIRE([LT_AC_PROG_SED]) +AC_REQUIRE([AC_PROG_NM]) +AC_REQUIRE([AC_OBJEXT]) +# Check for command to grab the raw symbol name followed by C symbol from nm. +AC_MSG_CHECKING([command to parse $NM output from $compiler object]) +AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe], +[ +# These are sane defaults that work on at least a few old systems. +# [They come from Ultrix. What could be older than Ultrix?!! ;)] + +# Character class describing NM global symbol codes. +symcode='[[BCDEGRST]]' + +# Regexp to match symbols that can be accessed directly from C. +sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)' + +# Transform an extracted symbol line into a proper C declaration +lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^. .* \(.*\)$/extern int \1;/p'" + +# Transform an extracted symbol line into symbol name and symbol address +lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" + +# Define system-specific variables. +case $host_os in +aix*) + symcode='[[BCDT]]' + ;; +cygwin* | mingw* | pw32*) + symcode='[[ABCDGISTW]]' + ;; +hpux*) # Its linker distinguishes data from code symbols + if test "$host_cpu" = ia64; then + symcode='[[ABCDEGRST]]' + fi + lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" + lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" + ;; +linux* | k*bsd*-gnu) + if test "$host_cpu" = ia64; then + symcode='[[ABCDGIRSTW]]' + lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" + lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" + fi + ;; +irix* | nonstopux*) + symcode='[[BCDEGRST]]' + ;; +osf*) + symcode='[[BCDEGQRST]]' + ;; +solaris*) + symcode='[[BDRT]]' + ;; +sco3.2v5*) + symcode='[[DT]]' + ;; +sysv4.2uw2*) + symcode='[[DT]]' + ;; +sysv5* | sco5v6* | unixware* | OpenUNIX*) + symcode='[[ABDT]]' + ;; +sysv4) + symcode='[[DFNSTU]]' + ;; +esac + +# Handle CRLF in mingw tool chain +opt_cr= +case $build_os in +mingw*) + opt_cr=`echo 'x\{0,1\}' | tr x '\015'` # option cr in regexp + ;; +esac + +# If we're using GNU nm, then use its standard symbol codes. +case `$NM -V 2>&1` in +*GNU* | *'with BFD'*) + symcode='[[ABCDGIRSTW]]' ;; +esac + +# Try without a prefix undercore, then with it. +for ac_symprfx in "" "_"; do + + # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. + symxfrm="\\1 $ac_symprfx\\2 \\2" + + # Write the raw and C identifiers. + lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" + + # Check to see that the pipe works correctly. + pipe_works=no + + rm -f conftest* + cat > conftest.$ac_ext < $nlist) && test -s "$nlist"; then + # Try sorting and uniquifying the output. + if sort "$nlist" | uniq > "$nlist"T; then + mv -f "$nlist"T "$nlist" + else + rm -f "$nlist"T + fi + + # Make sure that we snagged all the symbols we need. + if grep ' nm_test_var$' "$nlist" >/dev/null; then + if grep ' nm_test_func$' "$nlist" >/dev/null; then + cat < conftest.$ac_ext +#ifdef __cplusplus +extern "C" { +#endif + +EOF + # Now generate the symbol file. + eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | grep -v main >> conftest.$ac_ext' + + cat <> conftest.$ac_ext +#if defined (__STDC__) && __STDC__ +# define lt_ptr_t void * +#else +# define lt_ptr_t char * +# define const +#endif + +/* The mapping between symbol names and symbols. */ +const struct { + const char *name; + lt_ptr_t address; +} +lt_preloaded_symbols[[]] = +{ +EOF + $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (lt_ptr_t) \&\2},/" < "$nlist" | grep -v main >> conftest.$ac_ext + cat <<\EOF >> conftest.$ac_ext + {0, (lt_ptr_t) 0} +}; + +#ifdef __cplusplus +} +#endif +EOF + # Now try linking the two files. + mv conftest.$ac_objext conftstm.$ac_objext + lt_save_LIBS="$LIBS" + lt_save_CFLAGS="$CFLAGS" + LIBS="conftstm.$ac_objext" + CFLAGS="$CFLAGS$_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)" + if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then + pipe_works=yes + fi + LIBS="$lt_save_LIBS" + CFLAGS="$lt_save_CFLAGS" + else + echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD + fi + else + echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD + fi + else + echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD + fi + else + echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD + cat conftest.$ac_ext >&5 + fi + rm -rf conftest* conftst* + + # Do not use the global_symbol_pipe unless it works. + if test "$pipe_works" = yes; then + break + else + lt_cv_sys_global_symbol_pipe= + fi +done +]) +if test -z "$lt_cv_sys_global_symbol_pipe"; then + lt_cv_sys_global_symbol_to_cdecl= +fi +if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then + AC_MSG_RESULT(failed) +else + AC_MSG_RESULT(ok) +fi +]) # AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE + + +# AC_LIBTOOL_PROG_COMPILER_PIC([TAGNAME]) +# --------------------------------------- +AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC], +[_LT_AC_TAGVAR(lt_prog_compiler_wl, $1)= +_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= +_LT_AC_TAGVAR(lt_prog_compiler_static, $1)= + +AC_MSG_CHECKING([for $compiler option to produce PIC]) + ifelse([$1],[CXX],[ + # C++ specific cases for pic, static, wl, etc. + if test "$GXX" = yes; then + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + amigaos*) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' + ;; + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + mingw* | cygwin* | os2* | pw32*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + # Although the cygwin gcc ignores -fPIC, still need this for old-style + # (--disable-auto-import) libraries + m4_if([$1], [GCJ], [], + [_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) + ;; + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' + ;; + *djgpp*) + # DJGPP does not support shared libraries at all + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= + ;; + interix[[3-9]]*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + sysv4*MP*) + if test -d /usr/nec; then + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic + fi + ;; + hpux*) + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + else + case $host_os in + aix[[4-9]]*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + else + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' + fi + ;; + chorus*) + case $cc_basename in + cxch68*) + # Green Hills C++ Compiler + # _LT_AC_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" + ;; + esac + ;; + darwin*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + case $cc_basename in + xlc*) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-qnocommon' + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + ;; + esac + ;; + dgux*) + case $cc_basename in + ec++*) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + ;; + ghcx*) + # Green Hills C++ Compiler + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + *) + ;; + esac + ;; + freebsd* | dragonfly*) + # FreeBSD uses GNU C++ + ;; + hpux9* | hpux10* | hpux11*) + case $cc_basename in + CC*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' + if test "$host_cpu" != ia64; then + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + fi + ;; + aCC*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + ;; + esac + ;; + *) + ;; + esac + ;; + interix*) + # This is c89, which is MS Visual C++ (no shared libs) + # Anyone wants to do a port? + ;; + irix5* | irix6* | nonstopux*) + case $cc_basename in + CC*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + # CC pic flag -KPIC is the default. + ;; + *) + ;; + esac + ;; + linux* | k*bsd*-gnu) + case $cc_basename in + KCC*) + # KAI C++ Compiler + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + icpc* | ecpc*) + # Intel C++ + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + pgCC* | pgcpp*) + # Portland Group C++ compiler. + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + cxx*) + # Compaq C++ + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + ;; + esac + ;; + esac + ;; + lynxos*) + ;; + m88k*) + ;; + mvs*) + case $cc_basename in + cxx*) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall' + ;; + *) + ;; + esac + ;; + netbsd*) + ;; + osf3* | osf4* | osf5*) + case $cc_basename in + KCC*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' + ;; + RCC*) + # Rational C++ 2.4.1 + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + cxx*) + # Digital/Compaq C++ + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + *) + ;; + esac + ;; + psos*) + ;; + solaris*) + case $cc_basename in + CC*) + # Sun C++ 4.2, 5.x and Centerline C++ + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + ;; + gcx*) + # Green Hills C++ Compiler + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + ;; + *) + ;; + esac + ;; + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + lcc*) + # Lucid + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + *) + ;; + esac + ;; + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + ;; + *) + ;; + esac + ;; + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + case $cc_basename in + CC*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + esac + ;; + vxworks*) + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + esac + fi +], +[ + if test "$GCC" = yes; then + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + + amigaos*) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' + ;; + + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + + mingw* | cygwin* | pw32* | os2*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + # Although the cygwin gcc ignores -fPIC, still need this for old-style + # (--disable-auto-import) libraries + m4_if([$1], [GCJ], [], + [_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) + ;; + + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' + ;; + + interix[[3-9]]*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + + msdosdjgpp*) + # Just because we use GCC doesn't mean we suddenly get shared libraries + # on systems that don't support them. + _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + enable_shared=no + ;; + + sysv4*MP*) + if test -d /usr/nec; then + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic + fi + ;; + + hpux*) + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + ;; + + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + else + # PORTME Check for flag to pass linker flags through the system compiler. + case $host_os in + aix*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + else + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' + fi + ;; + darwin*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + case $cc_basename in + xlc*) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-qnocommon' + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + ;; + esac + ;; + + mingw* | cygwin* | pw32* | os2*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + m4_if([$1], [GCJ], [], + [_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) + ;; + + hpux9* | hpux10* | hpux11*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + ;; + esac + # Is there a better lt_prog_compiler_static that works with the bundled CC? + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' + ;; + + irix5* | irix6* | nonstopux*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # PIC (with -KPIC) is the default. + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + newsos6) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + linux* | k*bsd*-gnu) + case $cc_basename in + icc* | ecc*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + pgcc* | pgf77* | pgf90* | pgf95*) + # Portland Group compilers (*not* the Pentium gcc compiler, + # which looks to be a dead project) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + ccc*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # All Alpha code is PIC. + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C 5.9 + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + ;; + *Sun\ F*) + # Sun Fortran 8.3 passes all unrecognized flags to the linker + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='' + ;; + esac + ;; + esac + ;; + + osf3* | osf4* | osf5*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # All OSF/1 code is PIC. + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + rdos*) + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + solaris*) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + case $cc_basename in + f77* | f90* | f95*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';; + *) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';; + esac + ;; + + sunos4*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + sysv4 | sysv4.2uw2* | sysv4.3*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + sysv4*MP*) + if test -d /usr/nec ;then + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + unicos*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + + uts4*) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + *) + _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + esac + fi +]) +AC_MSG_RESULT([$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)]) + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)"; then + AC_LIBTOOL_COMPILER_OPTION([if $compiler PIC flag $_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) works], + _LT_AC_TAGVAR(lt_cv_prog_compiler_pic_works, $1), + [$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)ifelse([$1],[],[ -DPIC],[ifelse([$1],[CXX],[ -DPIC],[])])], [], + [case $_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) in + "" | " "*) ;; + *) _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)" ;; + esac], + [_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no]) +fi +case $host_os in + # For platforms which do not support PIC, -DPIC is meaningless: + *djgpp*) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)ifelse([$1],[],[ -DPIC],[ifelse([$1],[CXX],[ -DPIC],[])])" + ;; +esac + +# +# Check to make sure the static flag actually works. +# +wl=$_LT_AC_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_AC_TAGVAR(lt_prog_compiler_static, $1)\" +AC_LIBTOOL_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works], + _LT_AC_TAGVAR(lt_cv_prog_compiler_static_works, $1), + $lt_tmp_static_flag, + [], + [_LT_AC_TAGVAR(lt_prog_compiler_static, $1)=]) +]) + + +# AC_LIBTOOL_PROG_LD_SHLIBS([TAGNAME]) +# ------------------------------------ +# See if the linker supports building shared libraries. +AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS], +[AC_REQUIRE([LT_AC_PROG_SED])dnl +AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) +ifelse([$1],[CXX],[ + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + case $host_os in + aix[[4-9]]*) + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + if $NM -V 2>&1 | grep 'GNU' > /dev/null; then + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols' + else + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols' + fi + ;; + pw32*) + _LT_AC_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds" + ;; + cygwin* | mingw*) + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;/^.*[[ ]]__nm__/s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols' + ;; + *) + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + ;; + esac + _LT_AC_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] +],[ + runpath_var= + _LT_AC_TAGVAR(allow_undefined_flag, $1)= + _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=no + _LT_AC_TAGVAR(archive_cmds, $1)= + _LT_AC_TAGVAR(archive_expsym_cmds, $1)= + _LT_AC_TAGVAR(old_archive_From_new_cmds, $1)= + _LT_AC_TAGVAR(old_archive_from_expsyms_cmds, $1)= + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)= + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)= + _LT_AC_TAGVAR(thread_safe_flag_spec, $1)= + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)= + _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)= + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_minus_L, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + _LT_AC_TAGVAR(link_all_deplibs, $1)=unknown + _LT_AC_TAGVAR(hardcode_automatic, $1)=no + _LT_AC_TAGVAR(module_cmds, $1)= + _LT_AC_TAGVAR(module_expsym_cmds, $1)= + _LT_AC_TAGVAR(always_export_symbols, $1)=no + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + # include_expsyms should be a list of space-separated symbols to be *always* + # included in the symbol list + _LT_AC_TAGVAR(include_expsyms, $1)= + # exclude_expsyms can be an extended regexp of symbols to exclude + # it will be wrapped by ` (' and `)$', so one must not match beginning or + # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', + # as well as any symbol that contains `d'. + _LT_AC_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] + # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out + # platforms (ab)use it in PIC code, but their linkers get confused if + # the symbol is explicitly referenced. Since portable code cannot + # rely on this symbol name, it's probably fine to never include it in + # preloaded symbol tables. + # Exclude shared library initialization/finalization symbols. +dnl Note also adjust exclude_expsyms for C++ above. + extract_expsyms_cmds= + # Just being paranoid about ensuring that cc_basename is set. + _LT_CC_BASENAME([$compiler]) + case $host_os in + cygwin* | mingw* | pw32*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test "$GCC" != yes; then + with_gnu_ld=no + fi + ;; + interix*) + # we just hope/assume this is gcc and not c89 (= MSVC++) + with_gnu_ld=yes + ;; + openbsd*) + with_gnu_ld=no + ;; + esac + + _LT_AC_TAGVAR(ld_shlibs, $1)=yes + if test "$with_gnu_ld" = yes; then + # If archive_cmds runs LD, not CC, wlarc should be empty + wlarc='${wl}' + + # Set some defaults for GNU ld with shared library support. These + # are reset later if shared libraries are not supported. Putting them + # here allows them to be overridden if necessary. + runpath_var=LD_RUN_PATH + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + # ancient GNU ld didn't support --whole-archive et. al. + if $LD --help 2>&1 | grep 'no-whole-archive' > /dev/null; then + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)= + fi + supports_anon_versioning=no + case `$LD -v 2>/dev/null` in + *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11 + *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... + *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... + *\ 2.11.*) ;; # other 2.11 versions + *) supports_anon_versioning=yes ;; + esac + + # See if GNU ld supports shared libraries. + case $host_os in + aix[[3-9]]*) + # On AIX/PPC, the GNU linker is very broken + if test "$host_cpu" != ia64; then + _LT_AC_TAGVAR(ld_shlibs, $1)=no + cat <&2 + +*** Warning: the GNU linker, at least up to release 2.9.1, is reported +*** to be unable to reliably create shared libraries on AIX. +*** Therefore, libtool is disabling shared libraries support. If you +*** really care for shared libraries, you may want to modify your PATH +*** so that a non-GNU linker is found, and then restart. + +EOF + fi + ;; + + amigaos*) + _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + + # Samuel A. Falvo II reports + # that the semantics of dynamic libraries on AmigaOS, at least up + # to version 4, is to share data among multiple programs linked + # with the same dynamic library. Since this doesn't match the + # behavior of shared libraries on other platforms, we can't use + # them. + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + + beos*) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + cygwin* | mingw* | pw32*) + # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, + # as there is no search path for DLLs. + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_AC_TAGVAR(always_export_symbols, $1)=no + _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/'\'' -e '\''/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols' + + if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + interix[[3-9]]*) + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + + gnu* | linux* | k*bsd*-gnu) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + tmp_addflag= + case $cc_basename,$host_cpu in + pgcc*) # Portland Group C compiler + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag' + ;; + pgf77* | pgf90* | pgf95*) # Portland Group f77 and f90 compilers + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag -Mnomain' ;; + ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 + tmp_addflag=' -i_dynamic' ;; + efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 + tmp_addflag=' -i_dynamic -nofor_main' ;; + ifc* | ifort*) # Intel Fortran compiler + tmp_addflag=' -nofor_main' ;; + esac + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) # Sun C 5.9 + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_sharedflag='-G' ;; + *Sun\ F*) # Sun Fortran 8.3 + tmp_sharedflag='-G' ;; + *) + tmp_sharedflag='-shared' ;; + esac + _LT_AC_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + + if test $supports_anon_versioning = yes; then + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + $echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' + fi + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' + wlarc= + else + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + fi + ;; + + solaris*) + if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then + _LT_AC_TAGVAR(ld_shlibs, $1)=no + cat <&2 + +*** Warning: The releases 2.8.* of the GNU linker cannot reliably +*** create shared libraries on Solaris systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.9.1 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +EOF + elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) + case `$LD -v 2>&1` in + *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*) + _LT_AC_TAGVAR(ld_shlibs, $1)=no + cat <<_LT_EOF 1>&2 + +*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not +*** reliably create shared libraries on SCO systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.16.91.0.3 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + ;; + *) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='`test -z "$SCOABSPATH" && echo ${wl}-rpath,$libdir`' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname,\${SCOABSPATH:+${install_libdir}/}$soname,-retain-symbols-file,$export_symbols -o $lib' + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + sunos4*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' + wlarc= + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + + if test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = no; then + runpath_var= + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)= + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)= + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)= + fi + else + # PORTME fill in a description of your system's linker (not GNU ld) + case $host_os in + aix3*) + _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_AC_TAGVAR(always_export_symbols, $1)=yes + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + _LT_AC_TAGVAR(hardcode_direct, $1)=unsupported + fi + ;; + + aix[[4-9]]*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + if $NM -V 2>&1 | grep 'GNU' > /dev/null; then + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols' + else + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols' + fi + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) + for ld_flag in $LDFLAGS; do + if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then + aix_use_runtimelinking=yes + break + fi + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + _LT_AC_TAGVAR(archive_cmds, $1)='' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + + if test "$GCC" = yes; then + case $host_os in aix4.[[012]]|aix4.[[012]].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && \ + strings "$collect2name" | grep resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + _LT_AC_TAGVAR(hardcode_direct, $1)=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)= + fi + ;; + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to export. + _LT_AC_TAGVAR(always_export_symbols, $1)=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + _LT_AC_TAGVAR(allow_undefined_flag, $1)='-berok' + # Determine the default libpath from the value encoded in an empty executable. + _LT_AC_SYS_LIBPATH_AIX + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' + _LT_AC_TAGVAR(allow_undefined_flag, $1)="-z nodefs" + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an empty executable. + _LT_AC_SYS_LIBPATH_AIX + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + _LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' + # Exported symbols can be pulled into shared objects from archives + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='$convenience' + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes + # This is similar to how AIX traditionally builds its shared libraries. + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + amigaos*) + _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + # see comment about different semantics on the GNU ld section + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + + bsdi[[45]]*) + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic + ;; + + cygwin* | mingw* | pw32*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' + _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `echo "$deplibs" | $SED -e '\''s/ -lc$//'\''` -link -dll~linknames=' + # The linker will automatically build a .lib file if we build a DLL. + _LT_AC_TAGVAR(old_archive_From_new_cmds, $1)='true' + # FIXME: Should let the user specify the lib program. + _LT_AC_TAGVAR(old_archive_cmds, $1)='lib -OUT:$oldlib$oldobjs$old_deplibs' + _LT_AC_TAGVAR(fix_srcfile_path, $1)='`cygpath -w "$srcfile"`' + _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + ;; + + darwin* | rhapsody*) + case $host_os in + rhapsody* | darwin1.[[012]]) + _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-undefined ${wl}suppress' + ;; + *) # Darwin 1.3 on + if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' + else + case ${MACOSX_DEPLOYMENT_TARGET} in + 10.[[012]]) + _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' + ;; + 10.*) + _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-undefined ${wl}dynamic_lookup' + ;; + esac + fi + ;; + esac + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_automatic, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='' + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + if test "$GCC" = yes ; then + output_verbose_link_cmd='echo' + _LT_AC_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" + _LT_AC_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" + _LT_AC_TAGVAR(module_expsym_cmds, $1)="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" + else + case $cc_basename in + xlc*) + output_verbose_link_cmd='echo' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}`echo $rpath/$soname` $xlcverstring' + _LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' + # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}$rpath/$soname $xlcverstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + ;; + *) + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + fi + ;; + + dgux*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + freebsd1*) + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + + # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor + # support. Future versions do this automatically, but an explicit c++rt0.o + # does not break anything, and helps significantly (at the cost of a little + # extra space). + freebsd2.2*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + # Unfortunately, older versions of FreeBSD 2 do not have this feature. + freebsd2*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + # FreeBSD 3 and greater uses gcc -shared to do shared libraries. + freebsd* | dragonfly*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + hpux9*) + if test "$GCC" = yes; then + _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + fi + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + ;; + + hpux10*) + if test "$GCC" = yes -a "$with_gnu_ld" = no; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' + fi + if test "$with_gnu_ld" = no; then + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + fi + ;; + + hpux11*) + if test "$GCC" = yes -a "$with_gnu_ld" = no; then + case $host_cpu in + hppa*64*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + else + case $host_cpu in + hppa*64*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + fi + if test "$with_gnu_ld" = no; then + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + case $host_cpu in + hppa*64*|ia64*) + _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='+b $libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + *) + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + ;; + esac + fi + ;; + + irix5* | irix6* | nonstopux*) + if test "$GCC" = yes; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='-rpath $libdir' + fi + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out + else + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF + fi + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + newsos6) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + openbsd*) + if test -f /usr/libexec/ld.so; then + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + else + case $host_os in + openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + ;; + *) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + ;; + esac + fi + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + os2*) + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_AC_TAGVAR(archive_cmds, $1)='$echo "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$echo DATA >> $output_objdir/$libname.def~$echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~$echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' + _LT_AC_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' + ;; + + osf3*) + if test "$GCC" = yes; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + fi + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + + osf4* | osf5*) # as osf3* with the addition of -msym flag + if test "$GCC" = yes; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + else + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; echo "-hidden">> $lib.exp~ + $LD -shared${allow_undefined_flag} -input $lib.exp $linker_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib~$rm $lib.exp' + + # Both c and cxx compiler support -rpath directly + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + fi + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + + solaris*) + _LT_AC_TAGVAR(no_undefined_flag, $1)=' -z text' + if test "$GCC" = yes; then + wlarc='${wl}' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -shared ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$rm $lib.exp' + else + wlarc='' + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp' + fi + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) + # The compiler driver will combine and reorder linker options, + # but understands `-z linker_flag'. GCC discards it without `$wl', + # but is careful enough not to reorder. + # Supported since Solaris 2.6 (maybe 2.5.1?) + if test "$GCC" = yes; then + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' + else + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' + fi + ;; + esac + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + ;; + + sunos4*) + if test "x$host_vendor" = xsequent; then + # Use $CC to link under sequent, because it throws in some extra .o + # files that make .init and .fini sections work. + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' + fi + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + sysv4) + case $host_vendor in + sni) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes # is this really true??? + ;; + siemens) + ## LD is ld it makes a PLAMLIB + ## CC just makes a GrossModule. + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs' + _LT_AC_TAGVAR(hardcode_direct, $1)=no + ;; + motorola) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie + ;; + esac + runpath_var='LD_RUN_PATH' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + sysv4.3*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + _LT_AC_TAGVAR(ld_shlibs, $1)=yes + fi + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) + _LT_AC_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + _LT_AC_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs' + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + uts4*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *) + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + fi +]) +AC_MSG_RESULT([$_LT_AC_TAGVAR(ld_shlibs, $1)]) +test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no + +# +# Do we need to explicitly link libc? +# +case "x$_LT_AC_TAGVAR(archive_cmds_need_lc, $1)" in +x|xyes) + # Assume -lc should be added + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes + + if test "$enable_shared" = yes && test "$GCC" = yes; then + case $_LT_AC_TAGVAR(archive_cmds, $1) in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + AC_MSG_CHECKING([whether -lc should be explicitly linked in]) + $rm conftest* + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + if AC_TRY_EVAL(ac_compile) 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$_LT_AC_TAGVAR(lt_prog_compiler_wl, $1) + pic_flag=$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$_LT_AC_TAGVAR(allow_undefined_flag, $1) + _LT_AC_TAGVAR(allow_undefined_flag, $1)= + if AC_TRY_EVAL(_LT_AC_TAGVAR(archive_cmds, $1) 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1) + then + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + else + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes + fi + _LT_AC_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $rm conftest* + AC_MSG_RESULT([$_LT_AC_TAGVAR(archive_cmds_need_lc, $1)]) + ;; + esac + fi + ;; +esac +])# AC_LIBTOOL_PROG_LD_SHLIBS + + +# _LT_AC_FILE_LTDLL_C +# ------------------- +# Be careful that the start marker always follows a newline. +AC_DEFUN([_LT_AC_FILE_LTDLL_C], [ +# /* ltdll.c starts here */ +# #define WIN32_LEAN_AND_MEAN +# #include +# #undef WIN32_LEAN_AND_MEAN +# #include +# +# #ifndef __CYGWIN__ +# # ifdef __CYGWIN32__ +# # define __CYGWIN__ __CYGWIN32__ +# # endif +# #endif +# +# #ifdef __cplusplus +# extern "C" { +# #endif +# BOOL APIENTRY DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved); +# #ifdef __cplusplus +# } +# #endif +# +# #ifdef __CYGWIN__ +# #include +# DECLARE_CYGWIN_DLL( DllMain ); +# #endif +# HINSTANCE __hDllInstance_base; +# +# BOOL APIENTRY +# DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved) +# { +# __hDllInstance_base = hInst; +# return TRUE; +# } +# /* ltdll.c ends here */ +])# _LT_AC_FILE_LTDLL_C + + +# _LT_AC_TAGVAR(VARNAME, [TAGNAME]) +# --------------------------------- +AC_DEFUN([_LT_AC_TAGVAR], [ifelse([$2], [], [$1], [$1_$2])]) + + +# old names +AC_DEFUN([AM_PROG_LIBTOOL], [AC_PROG_LIBTOOL]) +AC_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)]) +AC_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)]) +AC_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)]) +AC_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)]) +AC_DEFUN([AM_PROG_LD], [AC_PROG_LD]) +AC_DEFUN([AM_PROG_NM], [AC_PROG_NM]) + +# This is just to silence aclocal about the macro not being used +ifelse([AC_DISABLE_FAST_INSTALL]) + +AC_DEFUN([LT_AC_PROG_GCJ], +[AC_CHECK_TOOL(GCJ, gcj, no) + test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2" + AC_SUBST(GCJFLAGS) +]) + +AC_DEFUN([LT_AC_PROG_RC], +[AC_CHECK_TOOL(RC, windres, no) +]) + + +# Cheap backport of AS_EXECUTABLE_P and required macros +# from Autoconf 2.59; we should not use $as_executable_p directly. + +# _AS_TEST_PREPARE +# ---------------- +m4_ifndef([_AS_TEST_PREPARE], +[m4_defun([_AS_TEST_PREPARE], +[if test -x / >/dev/null 2>&1; then + as_executable_p='test -x' +else + as_executable_p='test -f' +fi +])])# _AS_TEST_PREPARE + +# AS_EXECUTABLE_P +# --------------- +# Check whether a file is executable. +m4_ifndef([AS_EXECUTABLE_P], +[m4_defun([AS_EXECUTABLE_P], +[AS_REQUIRE([_AS_TEST_PREPARE])dnl +$as_executable_p $1[]dnl +])])# AS_EXECUTABLE_P + +# NOTE: This macro has been submitted for inclusion into # +# GNU Autoconf as AC_PROG_SED. When it is available in # +# a released version of Autoconf we should remove this # +# macro and use it instead. # +# LT_AC_PROG_SED +# -------------- +# Check for a fully-functional sed program, that truncates +# as few characters as possible. Prefer GNU sed if found. +AC_DEFUN([LT_AC_PROG_SED], +[AC_MSG_CHECKING([for a sed that does not truncate output]) +AC_CACHE_VAL(lt_cv_path_SED, +[# Loop through the user's path and test for sed and gsed. +# Then use that list of sed's as ones to test for truncation. +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for lt_ac_prog in sed gsed; do + for ac_exec_ext in '' $ac_executable_extensions; do + if AS_EXECUTABLE_P(["$as_dir/$lt_ac_prog$ac_exec_ext"]); then + lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext" + fi + done + done +done +IFS=$as_save_IFS +lt_ac_max=0 +lt_ac_count=0 +# Add /usr/xpg4/bin/sed as it is typically found on Solaris +# along with /bin/sed that truncates output. +for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do + test ! -f $lt_ac_sed && continue + cat /dev/null > conftest.in + lt_ac_count=0 + echo $ECHO_N "0123456789$ECHO_C" >conftest.in + # Check for GNU sed and select it if it is found. + if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then + lt_cv_path_SED=$lt_ac_sed + break + fi + while true; do + cat conftest.in conftest.in >conftest.tmp + mv conftest.tmp conftest.in + cp conftest.in conftest.nl + echo >>conftest.nl + $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break + cmp -s conftest.out conftest.nl || break + # 10000 chars as input seems more than enough + test $lt_ac_count -gt 10 && break + lt_ac_count=`expr $lt_ac_count + 1` + if test $lt_ac_count -gt $lt_ac_max; then + lt_ac_max=$lt_ac_count + lt_cv_path_SED=$lt_ac_sed + fi + done +done +]) +SED=$lt_cv_path_SED +AC_SUBST([SED]) +AC_MSG_RESULT([$SED]) +]) + +# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- +# +# Copyright © 2004 Scott James Remnant . +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# 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. + +# PKG_PROG_PKG_CONFIG([MIN-VERSION]) +# ---------------------------------- +AC_DEFUN([PKG_PROG_PKG_CONFIG], +[m4_pattern_forbid([^_?PKG_[A-Z_]+$]) +m4_pattern_allow([^PKG_CONFIG(_PATH)?$]) +AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility])dnl +if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then + AC_PATH_TOOL([PKG_CONFIG], [pkg-config]) +fi +if test -n "$PKG_CONFIG"; then + _pkg_min_version=m4_default([$1], [0.9.0]) + AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version]) + if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + PKG_CONFIG="" + fi + +fi[]dnl +])# PKG_PROG_PKG_CONFIG + +# PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) +# +# Check to see whether a particular set of modules exists. Similar +# to PKG_CHECK_MODULES(), but does not set variables or print errors. +# +# +# Similar to PKG_CHECK_MODULES, make sure that the first instance of +# this or PKG_CHECK_MODULES is called, or make sure to call +# PKG_CHECK_EXISTS manually +# -------------------------------------------------------------- +AC_DEFUN([PKG_CHECK_EXISTS], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl +if test -n "$PKG_CONFIG" && \ + AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then + m4_ifval([$2], [$2], [:]) +m4_ifvaln([$3], [else + $3])dnl +fi]) + + +# _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES]) +# --------------------------------------------- +m4_define([_PKG_CONFIG], +[if test -n "$$1"; then + pkg_cv_[]$1="$$1" + elif test -n "$PKG_CONFIG"; then + PKG_CHECK_EXISTS([$3], + [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null`], + [pkg_failed=yes]) + else + pkg_failed=untried +fi[]dnl +])# _PKG_CONFIG + +# _PKG_SHORT_ERRORS_SUPPORTED +# ----------------------------- +AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG]) +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi[]dnl +])# _PKG_SHORT_ERRORS_SUPPORTED + + +# PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], +# [ACTION-IF-NOT-FOUND]) +# +# +# Note that if there is a possibility the first call to +# PKG_CHECK_MODULES might not happen, you should be sure to include an +# explicit call to PKG_PROG_PKG_CONFIG in your configure.ac +# +# +# -------------------------------------------------------------- +AC_DEFUN([PKG_CHECK_MODULES], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl +AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl +AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl + +pkg_failed=no +AC_MSG_CHECKING([for $1]) + +_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2]) +_PKG_CONFIG([$1][_LIBS], [libs], [$2]) + +m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS +and $1[]_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details.]) + +if test $pkg_failed = yes; then + _PKG_SHORT_ERRORS_SUPPORTED + if test $_pkg_short_errors_supported = yes; then + $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors "$2" 2>&1` + else + $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors "$2" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD + + ifelse([$4], , [AC_MSG_ERROR(dnl +[Package requirements ($2) were not met: + +$$1_PKG_ERRORS + +Consider adjusting the PKG_CONFIG_PATH environment variable if you +installed software in a non-standard prefix. + +_PKG_TEXT +])], + [AC_MSG_RESULT([no]) + $4]) +elif test $pkg_failed = untried; then + ifelse([$4], , [AC_MSG_FAILURE(dnl +[The pkg-config script could not be found or is too old. Make sure it +is in your PATH or set the PKG_CONFIG environment variable to the full +path to pkg-config. + +_PKG_TEXT + +To get pkg-config, see .])], + [$4]) +else + $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS + $1[]_LIBS=$pkg_cv_[]$1[]_LIBS + AC_MSG_RESULT([yes]) + ifelse([$3], , :, [$3]) +fi[]dnl +])# PKG_CHECK_MODULES + +# Copyright (C) 2002, 2003, 2005, 2006, 2007 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.10' +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.10.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 AC_INIT_AUTOMAKE. +AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], +[AM_AUTOMAKE_VERSION([1.10.1])dnl +m4_ifndef([AC_AUTOCONF_VERSION], + [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl +_AM_AUTOCONF_VERSION(AC_AUTOCONF_VERSION)]) + +# AM_AUX_DIR_EXPAND -*- Autoconf -*- + +# Copyright (C) 2001, 2003, 2005 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], +[dnl Rely on autoconf to set up CDPATH properly. +AC_PREREQ([2.50])dnl +# expand $ac_aux_dir to an absolute path +am_aux_dir=`cd $ac_aux_dir && pwd` +]) + +# AM_CONDITIONAL -*- Autoconf -*- + +# Copyright (C) 1997, 2000, 2001, 2003, 2004, 2005, 2006 +# 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. + +# serial 8 + +# AM_CONDITIONAL(NAME, SHELL-CONDITION) +# ------------------------------------- +# Define a conditional. +AC_DEFUN([AM_CONDITIONAL], +[AC_PREREQ(2.52)dnl + ifelse([$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 +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, 2000, 2001, 2002, 2003, 2004, 2005, 2006 +# 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. + +# serial 9 + +# 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", "GCJ", or "OBJC". +# 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 + +ifelse([$1], CC, [depcc="$CC" am_compiler_list=], + [$1], CXX, [depcc="$CXX" am_compiler_list=], + [$1], OBJC, [depcc="$OBJC" 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'. + 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 + 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 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + case $depmode in + 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 + ;; + none) break ;; + esac + # 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. + if depmode=$depmode \ + source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} 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 sub/conftest.${OBJEXT-o} 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, +[ --disable-dependency-tracking speeds up one-time build + --enable-dependency-tracking do not reject slow dependency extractors]) +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' +fi +AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) +AC_SUBST([AMDEPBACKSLASH])dnl +_AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl +]) + +# Generate code to set up dependency tracking. -*- Autoconf -*- + +# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005 +# 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. + +#serial 3 + +# _AM_OUTPUT_DEPENDENCY_COMMANDS +# ------------------------------ +AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], +[for mf in $CONFIG_FILES; do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named `Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # Grep'ing the whole file is not good either: AIX grep has a line + # limit of 2048, but all sed's we know have understand at least 4000. + if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then + dirpart=`AS_DIRNAME("$mf")` + else + continue + fi + # Extract the definition of DEPDIR, am__include, and am__quote + # from the Makefile without running `make'. + DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` + test -z "$DEPDIR" && continue + am__include=`sed -n 's/^am__include = //p' < "$mf"` + test -z "am__include" && continue + am__quote=`sed -n 's/^am__quote = //p' < "$mf"` + # When using ansi2knr, U may be empty or an underscore; expand it + U=`sed -n 's/^U = //p' < "$mf"` + # Find all dependency output files, they are included files with + # $(DEPDIR) in their names. We invoke sed twice because it is the + # simplest approach to changing $(DEPDIR) to its actual value in the + # expansion. + for file in `sed -n " + s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`AS_DIRNAME(["$file"])` + AS_MKDIR_P([$dirpart/$fdir]) + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done +done +])# _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. FIXME. This creates each `.P' file that we will +# 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" ac_aux_dir="$ac_aux_dir"]) +]) + +# Do all the work for Automake. -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, +# 2005, 2006, 2008 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. + +# serial 13 + +# 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. + +# 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.60])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], +[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], 1)m4_ifdef([AC_PACKAGE_VERSION], 1), 11,, + [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) +AM_PROG_INSTALL_SH +AM_PROG_INSTALL_STRIP +AC_REQUIRE([AM_PROG_MKDIR_P])dnl +# We need awk for the "check" target. 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)], + [define([AC_PROG_CC], + defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl +AC_PROVIDE_IFELSE([AC_PROG_CXX], + [_AM_DEPENDENCIES(CXX)], + [define([AC_PROG_CXX], + defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl +AC_PROVIDE_IFELSE([AC_PROG_OBJC], + [_AM_DEPENDENCIES(OBJC)], + [define([AC_PROG_OBJC], + defn([AC_PROG_OBJC])[_AM_DEPENDENCIES(OBJC)])])dnl +]) +]) + + +# 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, 2003, 2005 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 +install_sh=${install_sh-"\$(SHELL) $am_aux_dir/install-sh"} +AC_SUBST(install_sh)]) + +# Copyright (C) 2003, 2005 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. + +# serial 2 + +# 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])]) + +# Add --enable-maintainer-mode option to configure. -*- Autoconf -*- +# From Jim Meyering + +# Copyright (C) 1996, 1998, 2000, 2001, 2002, 2003, 2004, 2005 +# 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. + +# serial 4 + +AC_DEFUN([AM_MAINTAINER_MODE], +[AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles]) + dnl maintainer-mode is disabled by default + AC_ARG_ENABLE(maintainer-mode, +[ --enable-maintainer-mode enable make rules and dependencies not useful + (and sometimes confusing) to the casual installer], + USE_MAINTAINER_MODE=$enableval, + USE_MAINTAINER_MODE=no) + AC_MSG_RESULT([$USE_MAINTAINER_MODE]) + AM_CONDITIONAL(MAINTAINER_MODE, [test $USE_MAINTAINER_MODE = yes]) + MAINT=$MAINTAINER_MODE_TRUE + AC_SUBST(MAINT)dnl +] +) + +AU_DEFUN([jm_MAINTAINER_MODE], [AM_MAINTAINER_MODE]) + +# Check to see how 'make' treats includes. -*- Autoconf -*- + +# Copyright (C) 2001, 2002, 2003, 2005 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. + +# serial 3 + +# AM_MAKE_INCLUDE() +# ----------------- +# Check to see how make treats includes. +AC_DEFUN([AM_MAKE_INCLUDE], +[am_make=${MAKE-make} +cat > confinc << 'END' +am__doit: + @echo done +.PHONY: am__doit +END +# If we don't find an include directive, just comment out the code. +AC_MSG_CHECKING([for style of include used by $am_make]) +am__include="#" +am__quote= +_am_result=none +# First try GNU make style include. +echo "include confinc" > confmf +# We grep out `Entering directory' and `Leaving directory' +# messages which can occur if `w' ends up in MAKEFLAGS. +# In particular we don't look at `^make:' because GNU make might +# be invoked under some other name (usually "gmake"), in which +# case it prints its new name instead of `make'. +if test "`$am_make -s -f confmf 2> /dev/null | grep -v 'ing directory'`" = "done"; then + am__include=include + am__quote= + _am_result=GNU +fi +# Now try BSD make style include. +if test "$am__include" = "#"; then + echo '.include "confinc"' > confmf + if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then + am__include=.include + am__quote="\"" + _am_result=BSD + fi +fi +AC_SUBST([am__include]) +AC_SUBST([am__quote]) +AC_MSG_RESULT([$_am_result]) +rm -f confinc confmf +]) + +# Copyright (C) 1999, 2000, 2001, 2003, 2004, 2005 +# 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. + +# serial 5 + +# AM_PROG_CC_C_O +# -------------- +# Like AC_PROG_CC_C_O, but changed for automake. +AC_DEFUN([AM_PROG_CC_C_O], +[AC_REQUIRE([AC_PROG_CC_C_O])dnl +AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +AC_REQUIRE_AUX_FILE([compile])dnl +# FIXME: we rely on the cache variable name because +# there is no other way. +set dummy $CC +ac_cc=`echo $[2] | sed ['s/[^a-zA-Z0-9_]/_/g;s/^[0-9]/_/']` +if eval "test \"`echo '$ac_cv_prog_cc_'${ac_cc}_c_o`\" != yes"; then + # Losing compiler, so override with the script. + # FIXME: It is wrong to rewrite CC. + # But if we don't then we get into trouble of one sort or another. + # A longer-term fix would be to have automake use am__CC in this case, + # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" + CC="$am_aux_dir/compile $CC" +fi +dnl Make sure AC_PROG_CC is never called again, or it will override our +dnl setting of CC. +m4_define([AC_PROG_CC], + [m4_fatal([AC_PROG_CC cannot be called after AM_PROG_CC_C_O])]) +]) + +# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- + +# Copyright (C) 1997, 1999, 2000, 2001, 2003, 2004, 2005 +# 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. + +# serial 5 + +# 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 supports --run. +# If it does, 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 +test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing" +# Use eval to expand $SHELL +if eval "$MISSING --run true"; then + am_missing_run="$MISSING --run " +else + am_missing_run= + AC_MSG_WARN([`missing' script is too old or missing]) +fi +]) + +# Copyright (C) 2003, 2004, 2005, 2006 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_MKDIR_P +# --------------- +# Check for `mkdir -p'. +AC_DEFUN([AM_PROG_MKDIR_P], +[AC_PREREQ([2.60])dnl +AC_REQUIRE([AC_PROG_MKDIR_P])dnl +dnl Automake 1.8 to 1.9.6 used to define mkdir_p. We now use MKDIR_P, +dnl while keeping a definition of mkdir_p for backward compatibility. +dnl @MKDIR_P@ is magic: AC_OUTPUT adjusts its value for each Makefile. +dnl However we cannot define mkdir_p as $(MKDIR_P) for the sake of +dnl Makefile.ins that do not define MKDIR_P, so we do our own +dnl adjustment using top_builddir (which is defined more often than +dnl MKDIR_P). +AC_SUBST([mkdir_p], ["$MKDIR_P"])dnl +case $mkdir_p in + [[\\/$]]* | ?:[[\\/]]*) ;; + */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;; +esac +]) + +# Helper functions for option handling. -*- Autoconf -*- + +# Copyright (C) 2001, 2002, 2003, 2005 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. + +# serial 3 + +# _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], +[AC_FOREACH([_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])]) + +# Check to make sure that the build environment is sane. -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005 +# 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. + +# serial 4 + +# AM_SANITY_CHECK +# --------------- +AC_DEFUN([AM_SANITY_CHECK], +[AC_MSG_CHECKING([whether build environment is sane]) +# Just in case +sleep 1 +echo timestamp > conftest.file +# 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 ( + 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 + rm -f conftest.file + 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 + + 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)]) + +# Copyright (C) 2001, 2003, 2005 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 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]) + +# Check how to create a tarball. -*- Autoconf -*- + +# Copyright (C) 2004, 2005 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. + +# serial 2 + +# _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. +AM_MISSING_PROG([AMTAR], [tar]) +m4_if([$1], [v7], + [am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'], + [m4_case([$1], [ustar],, [pax],, + [m4_fatal([Unknown tar format])]) +AC_MSG_CHECKING([how to create a $1 tar archive]) +# Loop over all known methods to create a tar archive until one works. +_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' +_am_tools=${am_cv_prog_tar_$1-$_am_tools} +# Do not fold the above two line into one, because Tru64 sh and +# Solaris sh will not grok spaces in the rhs of `-'. +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 + diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 0000000..62e5439 --- a/dev/null +++ b/autogen.sh @@ -0,0 +1,22 @@ +#!/bin/sh +# Run this to generate configure, Makefile.in's, etc + +(autoreconf --version) < /dev/null > /dev/null 2>&1 || { + (autoconf --version) < /dev/null > /dev/null 2>&1 || { + echo + echo "**Error**: You must have the GNU Build System (autoconf, automake, " + echo "libtool, etc) to update the ntfs-3g build system. Download the " + echo "appropriate packages for your distribution, or get the source " + echo "tar balls from ftp://ftp.gnu.org/pub/gnu/." + exit 1 + } + echo + echo "**Error**: Your version of autoconf is too old (you need at least 2.57)" + echo "to update the ntfs-3g build system. Download the appropriate " + echo "updated package for your distribution, or get the source tar ball " + echo "from ftp://ftp.gnu.org/pub/gnu/." + exit 1 +} + +echo Running autoreconf --verbose --install --force +autoreconf --verbose --install --force diff --git a/compile b/compile new file mode 100755 index 0000000..1b1d232 --- a/dev/null +++ b/compile @@ -0,0 +1,142 @@ +#! /bin/sh +# Wrapper for compilers which do not understand `-c -o'. + +scriptversion=2005-05-14.22 + +# Copyright (C) 1999, 2000, 2003, 2004, 2005 Free Software Foundation, Inc. +# Written by Tom Tromey . +# +# 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, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +# 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. + +# This file is maintained in Automake, please report +# bugs to or send patches to +# . + +case $1 in + '') + echo "$0: No command. Try \`$0 --help' for more information." 1>&2 + exit 1; + ;; + -h | --h*) + cat <<\EOF +Usage: compile [--help] [--version] PROGRAM [ARGS] + +Wrapper for compilers which do not understand `-c -o'. +Remove `-o dest.o' from ARGS, run PROGRAM with the remaining +arguments, and rename the output as expected. + +If you are trying to build a whole package this is not the +right script to run: please start by reading the file `INSTALL'. + +Report bugs to . +EOF + exit $? + ;; + -v | --v*) + echo "compile $scriptversion" + exit $? + ;; +esac + +ofile= +cfile= +eat= + +for arg +do + if test -n "$eat"; then + eat= + else + case $1 in + -o) + # configure might choose to run compile as `compile cc -o foo foo.c'. + # So we strip `-o arg' only if arg is an object. + eat=1 + case $2 in + *.o | *.obj) + ofile=$2 + ;; + *) + set x "$@" -o "$2" + shift + ;; + esac + ;; + *.c) + cfile=$1 + set x "$@" "$1" + shift + ;; + *) + set x "$@" "$1" + shift + ;; + esac + fi + shift +done + +if test -z "$ofile" || test -z "$cfile"; then + # If no `-o' option was seen then we might have been invoked from a + # pattern rule where we don't need one. That is ok -- this is a + # normal compilation that the losing compiler can handle. If no + # `.c' file was seen then we are probably linking. That is also + # ok. + exec "$@" +fi + +# Name of file we expect compiler to create. +cofile=`echo "$cfile" | sed -e 's|^.*/||' -e 's/\.c$/.o/'` + +# Create the lock directory. +# Note: use `[/.-]' here to ensure that we don't use the same name +# that we are using for the .o file. Also, base the name on the expected +# object file name, since that is what matters with a parallel build. +lockdir=`echo "$cofile" | sed -e 's|[/.-]|_|g'`.d +while true; do + if mkdir "$lockdir" >/dev/null 2>&1; then + break + fi + sleep 1 +done +# FIXME: race condition here if user kills between mkdir and trap. +trap "rmdir '$lockdir'; exit 1" 1 2 15 + +# Run the compile. +"$@" +ret=$? + +if test -f "$cofile"; then + mv "$cofile" "$ofile" +elif test -f "${cofile}bj"; then + mv "${cofile}bj" "$ofile" +fi + +rmdir "$lockdir" +exit $ret + +# 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-end: "$" +# End: diff --git a/config.guess b/config.guess new file mode 100755 index 0000000..e6b5d5b --- a/dev/null +++ b/config.guess @@ -0,0 +1,1536 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 +# Free Software Foundation, Inc. + +timestamp='2008-01-08' + +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA +# 02110-1301, USA. +# +# 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 Per Bothner . +# Please send patches to . Submit a context +# diff and a properly formatted ChangeLog entry. +# +# This script attempts to guess a canonical system name similar to +# config.sub. If it succeeds, it prints the system name on stdout, and +# exits with 0. Otherwise, it exits with 1. +# +# The plan is that this can be called by configure scripts if you +# don't specify an explicit build system type. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] + +Output the configuration name of the system \`$me' is run on. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.guess ($timestamp) + +Originally written by Per Bothner. +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, +2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" >&2 + exit 1 ;; + * ) + break ;; + esac +done + +if test $# != 0; then + echo "$me: too many arguments$help" >&2 + exit 1 +fi + +trap 'exit 1' 1 2 15 + +# CC_FOR_BUILD -- compiler used by this script. Note that the use of a +# compiler to aid in system detection is discouraged as it requires +# temporary files to be created and, as you can see below, it is a +# headache to deal with in a portable fashion. + +# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still +# use `HOST_CC' if defined, but it is deprecated. + +# Portable tmp directory creation inspired by the Autoconf team. + +set_cc_for_build=' +trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; +trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; +: ${TMPDIR=/tmp} ; + { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || + { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || + { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || + { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; +dummy=$tmp/dummy ; +tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; +case $CC_FOR_BUILD,$HOST_CC,$CC in + ,,) echo "int x;" > $dummy.c ; + for c in cc gcc c89 c99 ; do + if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then + CC_FOR_BUILD="$c"; break ; + fi ; + done ; + if test x"$CC_FOR_BUILD" = x ; then + CC_FOR_BUILD=no_compiler_found ; + fi + ;; + ,,*) CC_FOR_BUILD=$CC ;; + ,*,*) CC_FOR_BUILD=$HOST_CC ;; +esac ; set_cc_for_build= ;' + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 1994-08-24) +if (test -f /.attbin/uname) >/dev/null 2>&1 ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +case "${UNAME_MACHINE}" in + i?86) + test -z "$VENDOR" && VENDOR=pc + ;; + *) + test -z "$VENDOR" && VENDOR=unknown + ;; +esac +test -f /etc/SuSE-release -o -f /.buildenv && VENDOR=suse + +# Note: order is significant - the case branches are not exclusive. + +case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in + *:NetBSD:*:*) + # NetBSD (nbsd) targets should (where applicable) match one or + # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, + # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently + # switched to ELF, *-*-netbsd* would select the old + # object file format. This provides both forward + # compatibility and a consistent mechanism for selecting the + # object file format. + # + # Note: NetBSD doesn't particularly care about the vendor + # portion of the name. We always set it to "unknown". + sysctl="sysctl -n hw.machine_arch" + UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ + /usr/sbin/$sysctl 2>/dev/null || echo unknown)` + case "${UNAME_MACHINE_ARCH}" in + armeb) machine=armeb-unknown ;; + arm*) machine=arm-unknown ;; + sh3el) machine=shl-unknown ;; + sh3eb) machine=sh-unknown ;; + sh5el) machine=sh5le-unknown ;; + *) machine=${UNAME_MACHINE_ARCH}-unknown ;; + esac + # The Operating System including object format, if it has switched + # to ELF recently, or will in the future. + case "${UNAME_MACHINE_ARCH}" in + arm*|i386|m68k|ns32k|sh3*|sparc|vax) + eval $set_cc_for_build + if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep __ELF__ >/dev/null + then + # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). + # Return netbsd for either. FIX? + os=netbsd + else + os=netbsdelf + fi + ;; + *) + os=netbsd + ;; + esac + # The OS release + # Debian GNU/NetBSD machines have a different userland, and + # thus, need a distinct triplet. However, they do not need + # kernel version information, so it can be replaced with a + # suitable tag, in the style of linux-gnu. + case "${UNAME_VERSION}" in + Debian*) + release='-gnu' + ;; + *) + release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + ;; + esac + # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: + # contains redundant information, the shorter form: + # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. + echo "${machine}-${os}${release}" + exit ;; + *:OpenBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} + exit ;; + *:ekkoBSD:*:*) + echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} + exit ;; + *:SolidBSD:*:*) + echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} + exit ;; + macppc:MirBSD:*:*) + echo powerpc-unknown-mirbsd${UNAME_RELEASE} + exit ;; + *:MirBSD:*:*) + echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} + exit ;; + alpha:OSF1:*:*) + case $UNAME_RELEASE in + *4.0) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + ;; + *5.*) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` + ;; + esac + # According to Compaq, /usr/sbin/psrinfo has been available on + # OSF/1 and Tru64 systems produced since 1995. I hope that + # covers most systems running today. This code pipes the CPU + # types through head -n 1, so we only detect the type of CPU 0. + ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` + case "$ALPHA_CPU_TYPE" in + "EV4 (21064)") + UNAME_MACHINE="alpha" ;; + "EV4.5 (21064)") + UNAME_MACHINE="alpha" ;; + "LCA4 (21066/21068)") + UNAME_MACHINE="alpha" ;; + "EV5 (21164)") + UNAME_MACHINE="alphaev5" ;; + "EV5.6 (21164A)") + UNAME_MACHINE="alphaev56" ;; + "EV5.6 (21164PC)") + UNAME_MACHINE="alphapca56" ;; + "EV5.7 (21164PC)") + UNAME_MACHINE="alphapca57" ;; + "EV6 (21264)") + UNAME_MACHINE="alphaev6" ;; + "EV6.7 (21264A)") + UNAME_MACHINE="alphaev67" ;; + "EV6.8CB (21264C)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8AL (21264B)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8CX (21264D)") + UNAME_MACHINE="alphaev68" ;; + "EV6.9A (21264/EV69A)") + UNAME_MACHINE="alphaev69" ;; + "EV7 (21364)") + UNAME_MACHINE="alphaev7" ;; + "EV7.9 (21364A)") + UNAME_MACHINE="alphaev79" ;; + esac + # A Pn.n version is a patched version. + # A Vn.n version is a released version. + # A Tn.n version is a released field test version. + # A Xn.n version is an unreleased experimental baselevel. + # 1.2 uses "1.2" for uname -r. + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + exit ;; + Alpha\ *:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # Should we change UNAME_MACHINE based on the output of uname instead + # of the specific Alpha model? + echo alpha-pc-interix + exit ;; + 21064:Windows_NT:50:3) + echo alpha-dec-winnt3.5 + exit ;; + Amiga*:UNIX_System_V:4.0:*) + echo m68k-unknown-sysv4 + exit ;; + *:[Aa]miga[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-amigaos + exit ;; + *:[Mm]orph[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-morphos + exit ;; + *:OS/390:*:*) + echo i370-ibm-openedition + exit ;; + *:z/VM:*:*) + echo s390-ibm-zvmoe + exit ;; + *:OS400:*:*) + echo powerpc-ibm-os400 + exit ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix${UNAME_RELEASE} + exit ;; + arm:riscos:*:*|arm:RISCOS:*:*) + echo arm-unknown-riscos + exit ;; + SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) + echo hppa1.1-hitachi-hiuxmpp + exit ;; + Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) + # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. + if test "`(/bin/universe) 2>/dev/null`" = att ; then + echo pyramid-pyramid-sysv3 + else + echo pyramid-pyramid-bsd + fi + exit ;; + NILE*:*:*:dcosx) + echo pyramid-pyramid-svr4 + exit ;; + DRS?6000:unix:4.0:6*) + echo sparc-icl-nx6 + exit ;; + DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) + case `/usr/bin/uname -p` in + sparc) echo sparc-icl-nx7; exit ;; + esac ;; + sun4H:SunOS:5.*:*) + echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) + echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:*:*) + case "`/usr/bin/arch -k`" in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like `4.1.3-JL'. + echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` + exit ;; + sun3*:SunOS:*:*) + echo m68k-sun-sunos${UNAME_RELEASE} + exit ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` + test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 + case "`/bin/arch`" in + sun3) + echo m68k-sun-sunos${UNAME_RELEASE} + ;; + sun4) + echo sparc-sun-sunos${UNAME_RELEASE} + ;; + esac + exit ;; + aushp:SunOS:*:*) + echo sparc-auspex-sunos${UNAME_RELEASE} + exit ;; + # The situation for MiNT is a little confusing. The machine name + # can be virtually everything (everything which is not + # "atarist" or "atariste" at least should have a processor + # > m68000). The system name ranges from "MiNT" over "FreeMiNT" + # to the lowercase version "mint" (or "freemint"). Finally + # the system name "TOS" denotes a system which is actually not + # MiNT. But MiNT is downward compatible to TOS, so this should + # be no problem. + atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) + echo m68k-milan-mint${UNAME_RELEASE} + exit ;; + hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) + echo m68k-hades-mint${UNAME_RELEASE} + exit ;; + *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) + echo m68k-unknown-mint${UNAME_RELEASE} + exit ;; + m68k:machten:*:*) + echo m68k-apple-machten${UNAME_RELEASE} + exit ;; + powerpc:machten:*:*) + echo powerpc-apple-machten${UNAME_RELEASE} + exit ;; + RISC*:Mach:*:*) + echo mips-dec-mach_bsd4.3 + exit ;; + RISC*:ULTRIX:*:*) + echo mips-dec-ultrix${UNAME_RELEASE} + exit ;; + VAX*:ULTRIX*:*:*) + echo vax-dec-ultrix${UNAME_RELEASE} + exit ;; + 2020:CLIX:*:* | 2430:CLIX:*:*) + echo clipper-intergraph-clix${UNAME_RELEASE} + exit ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c +#ifdef __cplusplus +#include /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && + dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && + SYSTEM_NAME=`$dummy $dummyarg` && + { echo "$SYSTEM_NAME"; exit; } + echo mips-mips-riscos${UNAME_RELEASE} + exit ;; + Motorola:PowerMAX_OS:*:*) + echo powerpc-motorola-powermax + exit ;; + Motorola:*:4.3:PL8-*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:Power_UNIX:*:*) + echo powerpc-harris-powerunix + exit ;; + m88k:CX/UX:7*:*) + echo m88k-harris-cxux7 + exit ;; + m88k:*:4*:R4*) + echo m88k-motorola-sysv4 + exit ;; + m88k:*:3*:R3*) + echo m88k-motorola-sysv3 + exit ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] + then + if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ + [ ${TARGET_BINARY_INTERFACE}x = x ] + then + echo m88k-dg-dgux${UNAME_RELEASE} + else + echo m88k-dg-dguxbcs${UNAME_RELEASE} + fi + else + echo i586-dg-dgux${UNAME_RELEASE} + fi + exit ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + echo m88k-dolphin-sysv3 + exit ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + echo m88k-motorola-sysv3 + exit ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + echo m88k-tektronix-sysv3 + exit ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + echo m68k-tektronix-bsd + exit ;; + *:IRIX*:*:*) + echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` + exit ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id + exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i*86:AIX:*:*) + echo i386-ibm-aix + exit ;; + ia64:AIX:*:*) + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} + exit ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` + then + echo "$SYSTEM_NAME" + else + echo rs6000-ibm-aix3.2.5 + fi + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + echo rs6000-ibm-aix3.2.4 + else + echo rs6000-ibm-aix3.2 + fi + exit ;; + *:AIX:*:[456]) + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` + if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${IBM_ARCH}-ibm-aix${IBM_REV} + exit ;; + *:AIX:*:*) + echo rs6000-ibm-aix + exit ;; + ibmrt:4.4BSD:*|romp-ibm:BSD:*) + echo romp-ibm-bsd4.4 + exit ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and + echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to + exit ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + echo rs6000-bull-bosx + exit ;; + DPX/2?00:B.O.S.:*:*) + echo m68k-bull-sysv3 + exit ;; + 9000/[34]??:4.3bsd:1.*:*) + echo m68k-hp-bsd + exit ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + echo m68k-hp-bsd4.4 + exit ;; + 9000/[34678]??:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + case "${UNAME_MACHINE}" in + 9000/31? ) HP_ARCH=m68000 ;; + 9000/[34]?? ) HP_ARCH=m68k ;; + 9000/[678][0-9][0-9]) + if [ -x /usr/bin/getconf ]; then + sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` + sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` + case "${sc_cpu_version}" in + 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 + 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 + 532) # CPU_PA_RISC2_0 + case "${sc_kernel_bits}" in + 32) HP_ARCH="hppa2.0n" ;; + 64) HP_ARCH="hppa2.0w" ;; + '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 + esac ;; + esac + fi + if [ "${HP_ARCH}" = "" ]; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + + #define _HPUX_SOURCE + #include + #include + + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); + + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } +EOF + (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` + test -z "$HP_ARCH" && HP_ARCH=hppa + fi ;; + esac + if [ ${HP_ARCH} = "hppa2.0w" ] + then + eval $set_cc_for_build + + # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating + # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler + # generating 64-bit code. GNU and HP use different nomenclature: + # + # $ CC_FOR_BUILD=cc ./config.guess + # => hppa2.0w-hp-hpux11.23 + # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess + # => hppa64-hp-hpux11.23 + + if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | + grep __LP64__ >/dev/null + then + HP_ARCH="hppa2.0w" + else + HP_ARCH="hppa64" + fi + fi + echo ${HP_ARCH}-hp-hpux${HPUX_REV} + exit ;; + ia64:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + echo ia64-hp-hpux${HPUX_REV} + exit ;; + 3050*:HI-UX:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + echo unknown-hitachi-hiuxwe2 + exit ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) + echo hppa1.1-hp-bsd + exit ;; + 9000/8??:4.3bsd:*:*) + echo hppa1.0-hp-bsd + exit ;; + *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) + echo hppa1.0-hp-mpeix + exit ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) + echo hppa1.1-hp-osf + exit ;; + hp8??:OSF1:*:*) + echo hppa1.0-hp-osf + exit ;; + i*86:OSF1:*:*) + if [ -x /usr/sbin/sysversion ] ; then + echo ${UNAME_MACHINE}-unknown-osf1mk + else + echo ${UNAME_MACHINE}-unknown-osf1 + fi + exit ;; + parisc*:Lites*:*:*) + echo hppa1.1-hp-lites + exit ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + echo c1-convex-bsd + exit ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + echo c34-convex-bsd + exit ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + echo c38-convex-bsd + exit ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + echo c4-convex-bsd + exit ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*[A-Z]90:*:*:*) + echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ + -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*T3E:*:*:*) + echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*SV1:*:*:*) + echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + *:UNICOS/mp:*:*) + echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) + FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + 5000:UNIX_System_V:4.*:*) + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` + echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) + echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} + exit ;; + sparc*:BSD/OS:*:*) + echo sparc-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:BSD/OS:*:*) + echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:FreeBSD:*:*) + case ${UNAME_MACHINE} in + pc98) + echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + amd64) + echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + *) + echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + esac + exit ;; + i*:CYGWIN*:*) + echo ${UNAME_MACHINE}-pc-cygwin + exit ;; + *:MINGW*:*) + echo ${UNAME_MACHINE}-pc-mingw32 + exit ;; + i*:windows32*:*) + # uname -m includes "-pc" on this system. + echo ${UNAME_MACHINE}-mingw32 + exit ;; + i*:PW*:*) + echo ${UNAME_MACHINE}-pc-pw32 + exit ;; + *:Interix*:[3456]*) + case ${UNAME_MACHINE} in + x86) + echo i586-pc-interix${UNAME_RELEASE} + exit ;; + EM64T | authenticamd) + echo x86_64-unknown-interix${UNAME_RELEASE} + exit ;; + IA64) + echo ia64-unknown-interix${UNAME_RELEASE} + exit ;; + esac ;; + [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) + echo i${UNAME_MACHINE}-pc-mks + exit ;; + i*:Windows_NT*:* | Pentium*:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we + # UNAME_MACHINE based on the output of uname instead of i386? + echo i586-pc-interix + exit ;; + i*:UWIN*:*) + echo ${UNAME_MACHINE}-pc-uwin + exit ;; + amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) + echo x86_64-unknown-cygwin + exit ;; + p*:CYGWIN*:*) + echo powerpcle-unknown-cygwin + exit ;; + prep*:SunOS:5.*:*) + echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + *:GNU:*:*) + # the GNU system + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + exit ;; + *:GNU/*:*:*) + # other systems with GNU libc and userland + echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu + exit ;; + i*86:Minix:*:*) + echo ${UNAME_MACHINE}-pc-minix + exit ;; + arm*:Linux:*:*) + eval $set_cc_for_build + if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_EABI__ + then + echo ${UNAME_MACHINE}-${VENDOR}-linux-gnu + else + echo ${UNAME_MACHINE}-${VENDOR}-linux-gnueabi + fi + exit ;; + avr32*:Linux:*:*) + echo ${UNAME_MACHINE}-${VENDOR}-linux-gnu + exit ;; + cris:Linux:*:*) + echo cris-axis-linux-gnu + exit ;; + crisv32:Linux:*:*) + echo crisv32-axis-linux-gnu + exit ;; + frv:Linux:*:*) + echo frv-${VENDOR}-linux-gnu + exit ;; + ia64:Linux:*:*) + echo ${UNAME_MACHINE}-${VENDOR}-linux-gnu + exit ;; + m32r*:Linux:*:*) + echo ${UNAME_MACHINE}-${VENDOR}-linux-gnu + exit ;; + m68*:Linux:*:*) + echo ${UNAME_MACHINE}-${VENDOR}-linux-gnu + exit ;; + mips:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef mips + #undef mipsel + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=mipsel + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=mips + #else + CPU= + #endif + #endif +EOF + eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' + /^CPU/{ + s: ::g + p + }'`" + test x"${CPU}" != x && { echo "${CPU}-${VENDOR}-linux-gnu"; exit; } + ;; + mips64:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef mips64 + #undef mips64el + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=mips64el + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=mips64 + #else + CPU= + #endif + #endif +EOF + eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' + /^CPU/{ + s: ::g + p + }'`" + test x"${CPU}" != x && { echo "${CPU}-${VENDOR}-linux-gnu"; exit; } + ;; + or32:Linux:*:*) + echo or32-${VENDOR}-linux-gnu + exit ;; + ppc:Linux:*:*) + echo powerpc-${VENDOR}-linux-gnu + exit ;; + ppc64:Linux:*:*) + echo powerpc64-${VENDOR}-linux-gnu + exit ;; + alpha:Linux:*:*) + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in + EV5) UNAME_MACHINE=alphaev5 ;; + EV56) UNAME_MACHINE=alphaev56 ;; + PCA56) UNAME_MACHINE=alphapca56 ;; + PCA57) UNAME_MACHINE=alphapca56 ;; + EV6) UNAME_MACHINE=alphaev6 ;; + EV67) UNAME_MACHINE=alphaev67 ;; + EV68*) UNAME_MACHINE=alphaev68 ;; + esac + objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null + if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi + echo ${UNAME_MACHINE}-${VENDOR}-linux-gnu${LIBC} + exit ;; + parisc:Linux:*:* | hppa:Linux:*:*) + # Look for CPU level + case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in + PA7*) echo hppa1.1-${VENDOR}-linux-gnu ;; + PA8*) echo hppa2.0-${VENDOR}-linux-gnu ;; + *) echo hppa-${VENDOR}-linux-gnu ;; + esac + exit ;; + parisc64:Linux:*:* | hppa64:Linux:*:*) + echo hppa64-${VENDOR}-linux-gnu + exit ;; + s390:Linux:*:* | s390x:Linux:*:*) + echo ${UNAME_MACHINE}-ibm-linux + exit ;; + sh64*:Linux:*:*) + echo ${UNAME_MACHINE}-${VENDOR}-linux-gnu + exit ;; + sh*:Linux:*:*) + echo ${UNAME_MACHINE}-${VENDOR}-linux-gnu + exit ;; + sparc:Linux:*:* | sparc64:Linux:*:*) + echo ${UNAME_MACHINE}-${VENDOR}-linux-gnu + exit ;; + vax:Linux:*:*) + echo ${UNAME_MACHINE}-dec-linux-gnu + exit ;; + x86_64:Linux:*:*) + echo x86_64-${VENDOR}-linux-gnu + exit ;; + xtensa*:Linux:*:*) + echo ${UNAME_MACHINE}-${VENDOR}-linux-gnu + exit ;; + i*86:Linux:*:*) + # The BFD linker knows what the default object file format is, so + # first see if it will tell us. cd to the root directory to prevent + # problems with other programs or directories called `ld' in the path. + # Set LC_ALL=C to ensure ld outputs messages in English. + ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \ + | sed -ne '/supported targets:/!d + s/[ ][ ]*/ /g + s/.*supported targets: *// + s/ .*// + p'` + case "$ld_supported_targets" in + elf32-i386) + TENTATIVE="${UNAME_MACHINE}-${VENDOR}-linux-gnu" + ;; + a.out-i386-linux) + echo "${UNAME_MACHINE}-${VENDOR}-linux-gnuaout" + exit ;; + coff-i386) + echo "${UNAME_MACHINE}-${VENDOR}-linux-gnucoff" + exit ;; + "") + # Either a pre-BFD a.out linker (linux-gnuoldld) or + # one that does not give us useful --help. + echo "${UNAME_MACHINE}-${VENDOR}-linux-gnuoldld" + exit ;; + esac + # Determine whether the default compiler is a.out or elf + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + #ifdef __ELF__ + # ifdef __GLIBC__ + # if __GLIBC__ >= 2 + LIBC=gnu + # else + LIBC=gnulibc1 + # endif + # else + LIBC=gnulibc1 + # endif + #else + #if defined(__INTEL_COMPILER) || defined(__PGI) || defined(__SUNPRO_C) || defined(__SUNPRO_CC) + LIBC=gnu + #else + LIBC=gnuaout + #endif + #endif + #ifdef __dietlibc__ + LIBC=dietlibc + #endif +EOF + eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' + /^LIBC/{ + s: ::g + p + }'`" + test x"${LIBC}" != x && { + echo "${UNAME_MACHINE}-${VENDOR}-linux-${LIBC}" + exit + } + test x"${TENTATIVE}" != x && { echo "${TENTATIVE}"; exit; } + ;; + i*86:DYNIX/ptx:4*:*) + # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. + # earlier versions are messed up and put the nodename in both + # sysname and nodename. + echo i386-sequent-sysv4 + exit ;; + i*86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} + exit ;; + i*86:OS/2:*:*) + # If we were able to find `uname', then EMX Unix compatibility + # is probably installed. + echo ${UNAME_MACHINE}-pc-os2-emx + exit ;; + i*86:XTS-300:*:STOP) + echo ${UNAME_MACHINE}-unknown-stop + exit ;; + i*86:atheos:*:*) + echo ${UNAME_MACHINE}-unknown-atheos + exit ;; + i*86:syllable:*:*) + echo ${UNAME_MACHINE}-pc-syllable + exit ;; + i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*) + echo i386-unknown-lynxos${UNAME_RELEASE} + exit ;; + i*86:*DOS:*:*) + echo ${UNAME_MACHINE}-pc-msdosdjgpp + exit ;; + i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) + UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} + else + echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} + fi + exit ;; + i*86:*:5:[678]*) + # UnixWare 7.x, OpenUNIX and OpenServer 6. + case `/bin/uname -X | grep "^Machine"` in + *486*) UNAME_MACHINE=i486 ;; + *Pentium) UNAME_MACHINE=i586 ;; + *Pent*|*Celeron) UNAME_MACHINE=i686 ;; + esac + echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} + exit ;; + i*86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` + (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ + && UNAME_MACHINE=i686 + (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ + && UNAME_MACHINE=i686 + echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + else + echo ${UNAME_MACHINE}-pc-sysv32 + fi + exit ;; + pc:*:*:*) + # Left here for compatibility: + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i386. + echo i386-pc-msdosdjgpp + exit ;; + Intel:Mach:3*:*) + echo i386-pc-mach3 + exit ;; + paragon:*:*:*) + echo i860-intel-osf1 + exit ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 + fi + exit ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + echo m68010-convergent-sysv + exit ;; + mc68k:UNIX:SYSTEM5:3.51m) + echo m68k-convergent-sysv + exit ;; + M680?0:D-NIX:5.3:*) + echo m68k-diab-dnix + exit ;; + M68*:*:R3V[5678]*:*) + test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; + 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4; exit; } ;; + m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) + echo m68k-unknown-lynxos${UNAME_RELEASE} + exit ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos${UNAME_RELEASE} + exit ;; + rs6000:LynxOS:2.*:*) + echo rs6000-unknown-lynxos${UNAME_RELEASE} + exit ;; + PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*) + echo powerpc-unknown-lynxos${UNAME_RELEASE} + exit ;; + SM[BE]S:UNIX_SV:*:*) + echo mips-dde-sysv${UNAME_RELEASE} + exit ;; + RM*:ReliantUNIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + RM*:SINIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + echo ${UNAME_MACHINE}-sni-sysv4 + else + echo ns32k-sni-sysv + fi + exit ;; + PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says + echo i586-unisys-sysv4 + exit ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit ;; + i*86:VOS:*:*) + # From Paul.Green@stratus.com. + echo ${UNAME_MACHINE}-stratus-vos + exit ;; + *:VOS:*:*) + # From Paul.Green@stratus.com. + echo hppa1.1-stratus-vos + exit ;; + mc68*:A/UX:*:*) + echo m68k-apple-aux${UNAME_RELEASE} + exit ;; + news*:NEWS-OS:6*:*) + echo mips-sony-newsos6 + exit ;; + R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) + if [ -d /usr/nec ]; then + echo mips-nec-sysv${UNAME_RELEASE} + else + echo mips-unknown-sysv${UNAME_RELEASE} + fi + exit ;; + BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. + echo powerpc-be-beos + exit ;; + BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. + echo powerpc-apple-beos + exit ;; + BePC:BeOS:*:*) # BeOS running on Intel PC compatible. + echo i586-pc-beos + exit ;; + SX-4:SUPER-UX:*:*) + echo sx4-nec-superux${UNAME_RELEASE} + exit ;; + SX-5:SUPER-UX:*:*) + echo sx5-nec-superux${UNAME_RELEASE} + exit ;; + SX-6:SUPER-UX:*:*) + echo sx6-nec-superux${UNAME_RELEASE} + exit ;; + SX-7:SUPER-UX:*:*) + echo sx7-nec-superux${UNAME_RELEASE} + exit ;; + SX-8:SUPER-UX:*:*) + echo sx8-nec-superux${UNAME_RELEASE} + exit ;; + SX-8R:SUPER-UX:*:*) + echo sx8r-nec-superux${UNAME_RELEASE} + exit ;; + Power*:Rhapsody:*:*) + echo powerpc-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Rhapsody:*:*) + echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Darwin:*:*) + UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown + case $UNAME_PROCESSOR in + unknown) UNAME_PROCESSOR=powerpc ;; + esac + echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} + exit ;; + *:procnto*:*:* | *:QNX:[0123456789]*:*) + UNAME_PROCESSOR=`uname -p` + if test "$UNAME_PROCESSOR" = "x86"; then + UNAME_PROCESSOR=i386 + UNAME_MACHINE=pc + fi + echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} + exit ;; + *:QNX:*:4*) + echo i386-pc-qnx + exit ;; + NSE-?:NONSTOP_KERNEL:*:*) + echo nse-tandem-nsk${UNAME_RELEASE} + exit ;; + NSR-?:NONSTOP_KERNEL:*:*) + echo nsr-tandem-nsk${UNAME_RELEASE} + exit ;; + *:NonStop-UX:*:*) + echo mips-compaq-nonstopux + exit ;; + BS2000:POSIX*:*:*) + echo bs2000-siemens-sysv + exit ;; + DS/*:UNIX_System_V:*:*) + echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} + exit ;; + *:Plan9:*:*) + # "uname -m" is not consistent, so use $cputype instead. 386 + # is converted to i386 for consistency with other x86 + # operating systems. + if test "$cputype" = "386"; then + UNAME_MACHINE=i386 + else + UNAME_MACHINE="$cputype" + fi + echo ${UNAME_MACHINE}-unknown-plan9 + exit ;; + *:TOPS-10:*:*) + echo pdp10-unknown-tops10 + exit ;; + *:TENEX:*:*) + echo pdp10-unknown-tenex + exit ;; + KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) + echo pdp10-dec-tops20 + exit ;; + XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) + echo pdp10-xkl-tops20 + exit ;; + *:TOPS-20:*:*) + echo pdp10-unknown-tops20 + exit ;; + *:ITS:*:*) + echo pdp10-unknown-its + exit ;; + SEI:*:*:SEIUX) + echo mips-sei-seiux${UNAME_RELEASE} + exit ;; + *:DragonFly:*:*) + echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit ;; + *:*VMS:*:*) + UNAME_MACHINE=`(uname -p) 2>/dev/null` + case "${UNAME_MACHINE}" in + A*) echo alpha-dec-vms ; exit ;; + I*) echo ia64-dec-vms ; exit ;; + V*) echo vax-dec-vms ; exit ;; + esac ;; + *:XENIX:*:SysV) + echo i386-pc-xenix + exit ;; + i*86:skyos:*:*) + echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' + exit ;; + i*86:rdos:*:*) + echo ${UNAME_MACHINE}-pc-rdos + exit ;; +esac + +#echo '(No uname command or uname output not recognized.)' 1>&2 +#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 + +eval $set_cc_for_build +cat >$dummy.c < +# include +#endif +main () +{ +#if defined (sony) +#if defined (MIPSEB) + /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, + I don't know.... */ + printf ("mips-sony-bsd\n"); exit (0); +#else +#include + printf ("m68k-sony-newsos%s\n", +#ifdef NEWSOS4 + "4" +#else + "" +#endif + ); exit (0); +#endif +#endif + +#if defined (__arm) && defined (__acorn) && defined (__unix) + printf ("arm-acorn-riscix\n"); exit (0); +#endif + +#if defined (hp300) && !defined (hpux) + printf ("m68k-hp-bsd\n"); exit (0); +#endif + +#if defined (NeXT) +#if !defined (__ARCHITECTURE__) +#define __ARCHITECTURE__ "m68k" +#endif + int version; + version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; + if (version < 4) + printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); + else + printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); + exit (0); +#endif + +#if defined (MULTIMAX) || defined (n16) +#if defined (UMAXV) + printf ("ns32k-encore-sysv\n"); exit (0); +#else +#if defined (CMU) + printf ("ns32k-encore-mach\n"); exit (0); +#else + printf ("ns32k-encore-bsd\n"); exit (0); +#endif +#endif +#endif + +#if defined (__386BSD__) + printf ("i386-pc-bsd\n"); exit (0); +#endif + +#if defined (sequent) +#if defined (i386) + printf ("i386-sequent-dynix\n"); exit (0); +#endif +#if defined (ns32000) + printf ("ns32k-sequent-dynix\n"); exit (0); +#endif +#endif + +#if defined (_SEQUENT_) + struct utsname un; + + uname(&un); + + if (strncmp(un.version, "V2", 2) == 0) { + printf ("i386-sequent-ptx2\n"); exit (0); + } + if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ + printf ("i386-sequent-ptx1\n"); exit (0); + } + printf ("i386-sequent-ptx\n"); exit (0); + +#endif + +#if defined (vax) +# if !defined (ultrix) +# include +# if defined (BSD) +# if BSD == 43 + printf ("vax-dec-bsd4.3\n"); exit (0); +# else +# if BSD == 199006 + printf ("vax-dec-bsd4.3reno\n"); exit (0); +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# endif +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# else + printf ("vax-dec-ultrix\n"); exit (0); +# endif +#endif + +#if defined (alliant) && defined (i860) + printf ("i860-alliant-bsd\n"); exit (0); +#endif + + exit (1); +} +EOF + +$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + +# Apollos put the system type in the environment. + +test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } + +# Convex versions that predate uname can use getsysinfo(1) + +if [ -x /usr/convex/getsysinfo ] +then + case `getsysinfo -f cpu_type` in + c1*) + echo c1-convex-bsd + exit ;; + c2*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + c34*) + echo c34-convex-bsd + exit ;; + c38*) + echo c38-convex-bsd + exit ;; + c4*) + echo c4-convex-bsd + exit ;; + esac +fi + +cat >&2 < in order to provide the needed +information to handle your system. + +config.guess timestamp = $timestamp + +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` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null` + +hostinfo = `(hostinfo) 2>/dev/null` +/bin/universe = `(/bin/universe) 2>/dev/null` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` +/bin/arch = `(/bin/arch) 2>/dev/null` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` + +UNAME_MACHINE = ${UNAME_MACHINE} +UNAME_RELEASE = ${UNAME_RELEASE} +UNAME_SYSTEM = ${UNAME_SYSTEM} +UNAME_VERSION = ${UNAME_VERSION} +EOF + +exit 1 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/config.h b/config.h new file mode 100755 index 0000000..83d9e78 --- a/dev/null +++ b/config.h @@ -0,0 +1,361 @@ +#ifndef NTFS3G_CONFIG_H +#define NTFS3G_CONFIG_H +/* config.h. Generated from config.h.in by configure. */ +/* config.h.in. Generated from configure.ac by autoheader. */ + +/* Define to 1 if debug should be enabled */ +/* #undef ENABLE_DEBUG */ +//#define DEBUG + +/* Define to 1 if the nfconv patch should be enabled */ +/* #undef ENABLE_NFCONV */ + +/* Define to 1 if using internal fuse */ +#define FUSE_INTERNAL 1 + +/* Define to 1 if you have the `atexit' function. */ +#define HAVE_ATEXIT 1 + +/* Define to 1 if you have the `basename' function. */ +#define HAVE_BASENAME 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_BYTESWAP_H 1 + +/* Define to 1 if you have the `clock_gettime' function. */ +#define HAVE_CLOCK_GETTIME 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_CTYPE_H 1 + +/* Define to 1 if you have the `daemon' function. */ +#define HAVE_DAEMON 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_DLFCN_H 1 + +/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */ +/* #undef HAVE_DOPRNT */ + +/* Define to 1 if you have the `dup2' function. */ +#define HAVE_DUP2 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ENDIAN_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ERRNO_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_FCNTL_H 1 + +/* Define to 1 if you have the `fdatasync' function. */ +#define HAVE_FDATASYNC 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_FEATURES_H 1 + +/* Define to 1 if you have the `ffs' function. */ +#define HAVE_FFS 1 + +/* Define to 1 if you have the `fork' function. */ +#define HAVE_FORK 1 + +/* Define to 1 if you have the `getmntent' function. */ +#define HAVE_GETMNTENT + +/* Define to 1 if you have the header file. */ +#define HAVE_GETOPT_H 1 + +/* Define to 1 if you have the `getopt_long' function. */ +#define HAVE_GETOPT_LONG 1 + +/* Define to 1 if you have the `gettimeofday' function. */ +#define HAVE_GETTIMEOFDAY 1 + +/* Define to 1 if you have the `hasmntopt' function. */ +#define HAVE_HASMNTOPT 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_LIBGEN_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LIBINTL_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_LIMITS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_LINUX_FD_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_LINUX_HDREG_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_LINUX_MAJOR_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_LOCALE_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_MACHINE_ENDIAN_H */ + +/* Define to 1 if mbrtowc and mbstate_t are properly declared. */ +#define HAVE_MBRTOWC 1 + +/* Define to 1 if you have the `mbsinit' function. */ +#define HAVE_MBSINIT 1 + +/* Define to 1 if you have the `memmove' function. */ +#define HAVE_MEMMOVE 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the `memset' function. */ +#define HAVE_MEMSET 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_MNTENT_H 1 + #define MOUNTED "/etc/mtab" + +/* Define to 1 if you have the `realpath' function. */ +#define HAVE_REALPATH 1 + +/* Define to 1 if you have the `regcomp' function. */ +#define HAVE_REGCOMP 1 + +/* Define to 1 if you have the `setlocale' function. */ +#define HAVE_SETLOCALE 1 + +/* Define to 1 if you have the `setxattr' function. */ +//#define HAVE_SETXATTR 1 + +/* Define to 1 if `stat' has the bug that it succeeds when given the + zero-length file name argument. */ +#define HAVE_STAT_EMPTY_STRING_BUG 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDARG_H 1 + +/* Define to 1 if stdbool.h conforms to C99. */ +#define HAVE_STDBOOL_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDDEF_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDIO_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the `strcasecmp' function. */ +#define HAVE_STRCASECMP 1 + +/* Define to 1 if you have the `strchr' function. */ +#define HAVE_STRCHR 1 + +/* Define to 1 if you have the `strdup' function. */ +#define HAVE_STRDUP 1 + +/* Define to 1 if you have the `strerror' function. */ +#define HAVE_STRERROR 1 + +/* Define to 1 if you have the `strftime' function. */ +#define HAVE_STRFTIME 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the `strnlen' function. */ +#define HAVE_STRNLEN 1 + +/* Define to 1 if you have the `strsep' function. */ +#define HAVE_STRSEP 1 + +/* Define to 1 if you have the `strtol' function. */ +#define HAVE_STRTOL 1 + +/* Define to 1 if you have the `strtoul' function. */ +#define HAVE_STRTOUL 1 + +/* Define to 1 if `st_atim' is member of `struct stat'. */ +/* #undef HAVE_STRUCT_STAT_ST_ATIM */ + +/* Define to 1 if `st_atimensec' is member of `struct stat'. */ +#define HAVE_STRUCT_STAT_ST_ATIMENSEC 1 + +/* Define to 1 if `st_atimespec' is member of `struct stat'. */ +/* #undef HAVE_STRUCT_STAT_ST_ATIMESPEC */ + +/* Define to 1 if `st_blocks' is member of `struct stat'. */ +#define HAVE_STRUCT_STAT_ST_BLOCKS 1 + +/* Define to 1 if `st_rdev' is member of `struct stat'. */ +#define HAVE_STRUCT_STAT_ST_RDEV 1 + +/* Define to 1 if your `struct stat' has `st_blocks'. Deprecated, use + `HAVE_STRUCT_STAT_ST_BLOCKS' instead. */ +#define HAVE_ST_BLOCKS 1 + +/* Define to 1 if you have the `sysconf' function. */ +#define HAVE_SYSCONF 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYSLOG_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_BYTEORDER_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_ENDIAN_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_IOCTL_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_MKDEV_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_MOUNT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_PARAM_H 1 + +/* Define to 1 if you have the header file. */ +//#define HAVE_SYS_STATVFS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_SYSMACROS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 0 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_VFS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_TIME_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + #define __USE_FILE_OFFSET64 + + +/* Define to 1 if you have the `utime' function. */ +#define HAVE_UTIME 1 + +/* Define to 1 if you have the `utimensat' function. */ +/* #undef HAVE_UTIMENSAT */ + +/* Define to 1 if you have the header file. */ +#define HAVE_UTIME_H 1 + +/* Define to 1 if `utime(file, NULL)' sets file's timestamp to the present. */ +/* #undef HAVE_UTIME_NULL */ + +/* Define to 1 if you have the `vprintf' function. */ +#define HAVE_VPRINTF 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_WCHAR_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_WINDOWS_H */ + +/* Define to 1 if the system has the type `_Bool'. */ +#define HAVE__BOOL 1 + +/* Don't update /etc/mtab */ +/* #undef IGNORE_MTAB */ + +/* Define to 1 if `lstat' dereferences a symlink specified with a trailing + slash. */ +/* #undef LSTAT_FOLLOWS_SLASHED_SYMLINK */ + +/* Define to 1 if your C compiler doesn't accept -c and -o together. */ +/* #undef NO_MINUS_C_MINUS_O */ + +/* Don't use default IO ops */ +/* #undef NO_NTFS_DEVICE_DEFAULT_IO_OPS */ + +/* Name of package */ +#define PACKAGE "ntfs-3g" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "ntfs-3g-devel@lists.sf.net" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "ntfs-3g" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "ntfs-3g 2010.5.16" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "ntfs-3g" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "2010.5.16" + +/* POSIX ACL support */ +/* #undef POSIXACLS */ + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Version number of package */ +#define VERSION "2010.5.16" + +/* Define to 1 if this is a Windows OS */ +/* #undef WINDOWS */ + +/* Define to 1 if your processor stores words with the most significant byte + first (like Motorola and SPARC, unlike Intel and VAX). */ +/* #undef WORDS_BIGENDIAN */ + +/* Define to 1 if your processor stores words with the least significant byte + first (like Intel and VAX, unlike Motorola and SPARC). */ +#define WORDS_LITTLEENDIAN 1 + +/* Number of bits in a file offset, on hosts where this is settable. */ +#define _FILE_OFFSET_BITS 64 + +/* Enable GNU extensions on systems that have them. */ +#ifndef _GNU_SOURCE +# define _GNU_SOURCE 1 +#endif + +/* Define for large files, on AIX-style hosts. */ +/* #undef _LARGE_FILES */ + +/* Required define if using POSIX threads */ +#define _REENTRANT 1 + +#define _PATH_MOUNTED "/etc/mtab" + +/* Define to `__inline__' or `__inline' if that's what the C compiler + calls it, or to nothing if 'inline' is not supported under any name. */ +#ifndef __cplusplus +/* #undef inline */ +#endif + +/* Define to `long int' if does not define. */ +/* #undef off_t */ + +/* Define to `unsigned int' if does not define. */ +/* #undef size_t */ +#endif + diff --git a/config.h.in b/config.h.in new file mode 100755 index 0000000..49c2cf5 --- a/dev/null +++ b/config.h.in @@ -0,0 +1,350 @@ +/* config.h.in. Generated from configure.ac by autoheader. */ + +/* Define to 1 if debug should be enabled */ +#undef ENABLE_DEBUG + +/* Define to 1 if the nfconv patch should be enabled */ +#undef ENABLE_NFCONV + +/* Define to 1 if using internal fuse */ +#undef FUSE_INTERNAL + +/* Define to 1 if you have the `atexit' function. */ +#undef HAVE_ATEXIT + +/* Define to 1 if you have the `basename' function. */ +#undef HAVE_BASENAME + +/* Define to 1 if you have the header file. */ +#undef HAVE_BYTESWAP_H + +/* Define to 1 if you have the `clock_gettime' function. */ +#undef HAVE_CLOCK_GETTIME + +/* Define to 1 if you have the header file. */ +#undef HAVE_CTYPE_H + +/* Define to 1 if you have the `daemon' function. */ +#undef HAVE_DAEMON + +/* Define to 1 if you have the header file. */ +#undef HAVE_DLFCN_H + +/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */ +#undef HAVE_DOPRNT + +/* Define to 1 if you have the `dup2' function. */ +#undef HAVE_DUP2 + +/* Define to 1 if you have the header file. */ +#undef HAVE_ENDIAN_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_ERRNO_H + +/* 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 `ffs' function. */ +#undef HAVE_FFS + +/* Define to 1 if you have the `fork' function. */ +#undef HAVE_FORK + +/* Define to 1 if you have the `getmntent' function. */ +#undef HAVE_GETMNTENT + +/* Define to 1 if you have the header file. */ +#undef HAVE_GETOPT_H + +/* Define to 1 if you have the `getopt_long' function. */ +#undef HAVE_GETOPT_LONG + +/* Define to 1 if you have the `gettimeofday' function. */ +#undef HAVE_GETTIMEOFDAY + +/* Define to 1 if you have the `hasmntopt' function. */ +#undef HAVE_HASMNTOPT + +/* Define to 1 if you have the header file. */ +#undef HAVE_INTTYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_LIBGEN_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_LIBINTL_H + +/* 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_FD_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_LINUX_HDREG_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_LINUX_MAJOR_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_LOCALE_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_MACHINE_ENDIAN_H + +/* Define to 1 if mbrtowc and mbstate_t are properly declared. */ +#undef HAVE_MBRTOWC + +/* Define to 1 if you have the `mbsinit' function. */ +#undef HAVE_MBSINIT + +/* 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 header file. */ +#undef HAVE_MNTENT_H + +/* Define to 1 if you have the `realpath' function. */ +#undef HAVE_REALPATH + +/* Define to 1 if you have the `regcomp' function. */ +#undef HAVE_REGCOMP + +/* Define to 1 if you have the `setlocale' function. */ +#undef HAVE_SETLOCALE + +/* Define to 1 if you have the `setxattr' function. */ +#undef HAVE_SETXATTR + +/* Define to 1 if `stat' has the bug that it succeeds when given the + zero-length file name argument. */ +#undef HAVE_STAT_EMPTY_STRING_BUG + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDARG_H + +/* Define to 1 if stdbool.h conforms to C99. */ +#undef HAVE_STDBOOL_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 to 1 if you have the `strcasecmp' function. */ +#undef HAVE_STRCASECMP + +/* Define to 1 if you have the `strchr' function. */ +#undef HAVE_STRCHR + +/* Define to 1 if you have the `strdup' function. */ +#undef HAVE_STRDUP + +/* 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 you have the `strnlen' function. */ +#undef HAVE_STRNLEN + +/* Define to 1 if you have the `strsep' function. */ +#undef HAVE_STRSEP + +/* Define to 1 if you have the `strtol' function. */ +#undef HAVE_STRTOL + +/* Define to 1 if you have the `strtoul' function. */ +#undef HAVE_STRTOUL + +/* Define to 1 if `st_atim' is member of `struct stat'. */ +#undef HAVE_STRUCT_STAT_ST_ATIM + +/* Define to 1 if `st_atimensec' is member of `struct stat'. */ +#undef HAVE_STRUCT_STAT_ST_ATIMENSEC + +/* Define to 1 if `st_atimespec' is member of `struct stat'. */ +#undef HAVE_STRUCT_STAT_ST_ATIMESPEC + +/* Define to 1 if `st_blocks' is member of `struct stat'. */ +#undef HAVE_STRUCT_STAT_ST_BLOCKS + +/* Define to 1 if `st_rdev' is member of `struct stat'. */ +#undef HAVE_STRUCT_STAT_ST_RDEV + +/* Define to 1 if your `struct stat' has `st_blocks'. Deprecated, use + `HAVE_STRUCT_STAT_ST_BLOCKS' instead. */ +#undef HAVE_ST_BLOCKS + +/* Define to 1 if you have the `sysconf' function. */ +#undef HAVE_SYSCONF + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYSLOG_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_BYTEORDER_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_ENDIAN_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_MKDEV_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_SYSMACROS_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_VFS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_TIME_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define to 1 if you have the `utime' function. */ +#undef HAVE_UTIME + +/* Define to 1 if you have the `utimensat' function. */ +#undef HAVE_UTIMENSAT + +/* Define to 1 if you have the header file. */ +#undef HAVE_UTIME_H + +/* Define to 1 if `utime(file, NULL)' sets file's timestamp to the present. */ +#undef HAVE_UTIME_NULL + +/* Define to 1 if you have the `vprintf' function. */ +#undef HAVE_VPRINTF + +/* Define to 1 if you have the header file. */ +#undef HAVE_WCHAR_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_WINDOWS_H + +/* Define to 1 if the system has the type `_Bool'. */ +#undef HAVE__BOOL + +/* Don't update /etc/mtab */ +#undef IGNORE_MTAB + +/* Define to 1 if `lstat' dereferences a symlink specified with a trailing + slash. */ +#undef LSTAT_FOLLOWS_SLASHED_SYMLINK + +/* Define to 1 if your C compiler doesn't accept -c and -o together. */ +#undef NO_MINUS_C_MINUS_O + +/* Don't use default IO ops */ +#undef NO_NTFS_DEVICE_DEFAULT_IO_OPS + +/* 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 version of this package. */ +#undef PACKAGE_VERSION + +/* POSIX ACL support */ +#undef POSIXACLS + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Version number of package */ +#undef VERSION + +/* Define to 1 if this is a Windows OS */ +#undef WINDOWS + +/* Define to 1 if your processor stores words with the most significant byte + first (like Motorola and SPARC, unlike Intel and VAX). */ +#undef WORDS_BIGENDIAN + +/* Define to 1 if your processor stores words with the least significant byte + first (like Intel and VAX, unlike Motorola and SPARC). */ +#undef WORDS_LITTLEENDIAN + +/* Number of bits in a file offset, on hosts where this is settable. */ +#undef _FILE_OFFSET_BITS + +/* Enable GNU extensions on systems that have them. */ +#ifndef _GNU_SOURCE +# undef _GNU_SOURCE +#endif + +/* Define for large files, on AIX-style hosts. */ +#undef _LARGE_FILES + +/* Required define if using POSIX threads */ +#undef _REENTRANT + +/* Define to `__inline__' or `__inline' if that's what the C compiler + calls it, or to nothing if 'inline' is not supported under any name. */ +#ifndef __cplusplus +#undef inline +#endif + +/* Define to `long int' if does not define. */ +#undef off_t + +/* Define to `unsigned int' if does not define. */ +#undef size_t diff --git a/config.log b/config.log new file mode 100755 index 0000000..3f928ac --- a/dev/null +++ b/config.log @@ -0,0 +1,3290 @@ +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by ntfs-3g configure 2010.5.16, which was +generated by GNU Autoconf 2.61. Invocation command line was + + $ ./configure CC=arc-linux-uclibc-gcc --prefix=/mnt/fileroot/michael.wang/linux-top-pub/ui_ref/trunk/bld_7266_h_64x2/./rootfs --host=arc-linux-uclibc CFLAGS=-mA7 -g --enable-mount-helper=no --enable-ldconfig=no exec_prefix=/mnt/fileroot/michael.wang/linux-top-pub/ui_ref/trunk/bld_7266_h_64x2/./rootfs + +## --------- ## +## Platform. ## +## --------- ## + +hostname = announce +uname -m = i686 +uname -r = 2.6.31-14-generic-pae +uname -s = Linux +uname -v = #48-Ubuntu SMP Fri Oct 16 15:22:42 UTC 2009 + +/usr/bin/uname -p = unknown +/bin/uname -X = unknown + +/bin/arch = unknown +/usr/bin/arch -k = unknown +/usr/convex/getsysinfo = unknown +/usr/bin/hostinfo = unknown +/bin/machine = unknown +/usr/bin/oslevel = unknown +/bin/universe = unknown + +PATH: /usr/local/sbin +PATH: /usr/local/bin +PATH: /usr/sbin +PATH: /usr/bin +PATH: /sbin +PATH: /bin +PATH: /usr/games +PATH: /opt/gnutools/arc2.3-p0/elf32-4.2.1/bin +PATH: /opt/gnutools/arc2.3-p0/uclibc-4.2.1/bin +PATH: . +PATH: /opt/qtcreator-1.2.0/bin + + +## ----------- ## +## Core tests. ## +## ----------- ## + +configure:2048: checking build system type +configure:2066: result: i686-pc-linux-gnu +configure:2088: checking host system type +configure:2103: result: arc-unknown-linux-uclibc +configure:2125: checking target system type +configure:2140: result: arc-unknown-linux-uclibc +configure:2185: checking for a BSD-compatible install +configure:2241: result: /usr/bin/install -c +configure:2252: checking whether build environment is sane +configure:2295: result: yes +configure:2323: checking for a thread-safe mkdir -p +configure:2362: result: /bin/mkdir -p +configure:2375: checking for gawk +configure:2405: result: no +configure:2375: checking for mawk +configure:2391: found /usr/bin/mawk +configure:2402: result: mawk +configure:2413: checking whether make sets $(MAKE) +configure:2434: result: yes +configure:2514: checking for arc-linux-uclibc-strip +configure:2530: found /opt/gnutools/arc2.3-p0/uclibc-4.2.1/bin/arc-linux-uclibc-strip +configure:2541: result: arc-linux-uclibc-strip +configure:2625: checking whether to enable maintainer-specific portions of Makefiles +configure:2634: result: no +configure:2786: checking for arc-linux-uclibc-gcc +configure:2813: result: arc-linux-uclibc-gcc +configure:2893: checking for C compiler version +configure:2900: arc-linux-uclibc-gcc --version >&5 +arc-linux-uclibc-gcc (GCC) 4.2.1 (ARC_2.3) +Copyright (C) 2007 Free Software Foundation, Inc. +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +configure:2903: $? = 0 +configure:2910: arc-linux-uclibc-gcc -v >&5 +Using built-in specs. +Target: arc-linux-uclibc +Configured with: ../src/configure --target=arc-linux-uclibc --prefix=/opt/gnutools/arc2.3-p0/uclibc-4.2.1 --with-headers=/opt/gnutools/arc2.3-p0/uclibc-4.2.1/arc-linux-uclibc/include --enable-shared --disable-multilib --without-newlib --enable-languages=c,c++ --with-cpu=arc700 --disable-c99 +Thread model: posix +gcc version 4.2.1 (ARC_2.3) +configure:2913: $? = 0 +configure:2920: arc-linux-uclibc-gcc -V >&5 +arc-linux-uclibc-gcc: '-V' option must have argument +configure:2923: $? = 1 +configure:2946: checking for C compiler default output file name +configure:2973: arc-linux-uclibc-gcc -mA7 -g conftest.c >&5 +configure:2976: $? = 0 +configure:3014: result: a.out +configure:3031: checking whether the C compiler works +configure:3041: ./a.out +./configure: line 3042: ./a.out: cannot execute binary file +configure:3044: $? = 126 +configure:3061: result: yes +configure:3068: checking whether we are cross compiling +configure:3070: result: yes +configure:3073: checking for suffix of executables +configure:3080: arc-linux-uclibc-gcc -o conftest -mA7 -g conftest.c >&5 +configure:3083: $? = 0 +configure:3107: result: +configure:3113: checking for suffix of object files +configure:3139: arc-linux-uclibc-gcc -c -mA7 -g conftest.c >&5 +configure:3142: $? = 0 +configure:3165: result: o +configure:3169: checking whether we are using the GNU C compiler +configure:3198: arc-linux-uclibc-gcc -c -mA7 -g conftest.c >&5 +configure:3204: $? = 0 +configure:3221: result: yes +configure:3226: checking whether arc-linux-uclibc-gcc accepts -g +configure:3256: arc-linux-uclibc-gcc -c -g conftest.c >&5 +configure:3262: $? = 0 +configure:3361: result: yes +configure:3378: checking for arc-linux-uclibc-gcc option to accept ISO C89 +configure:3452: arc-linux-uclibc-gcc -c -mA7 -g conftest.c >&5 +configure:3458: $? = 0 +configure:3481: result: none needed +configure:3510: checking for style of include used by make +configure:3538: result: GNU +configure:3563: checking dependency style of arc-linux-uclibc-gcc +configure:3654: result: gcc3 +configure:3669: checking whether ln -s works +configure:3673: result: yes +configure:3681: checking whether arc-linux-uclibc-gcc and cc understand -c and -o together +configure:3716: arc-linux-uclibc-gcc -c conftest.c -o conftest2.o >&5 +configure:3719: $? = 0 +configure:3725: arc-linux-uclibc-gcc -c conftest.c -o conftest2.o >&5 +configure:3728: $? = 0 +configure:3739: cc -c conftest.c >&5 +configure:3742: $? = 0 +configure:3750: cc -c conftest.c -o conftest2.o >&5 +configure:3753: $? = 0 +configure:3759: cc -c conftest.c -o conftest2.o >&5 +configure:3762: $? = 0 +configure:3780: result: yes +configure:3879: checking for a sed that does not truncate output +configure:3935: result: /bin/sed +configure:3938: checking for grep that handles long lines and -e +configure:4012: result: /bin/grep +configure:4017: checking for egrep +configure:4095: result: /bin/grep -E +configure:4111: checking for ld used by arc-linux-uclibc-gcc +configure:4178: result: /opt/gnutools/arc2.3-p0/uclibc-4.2.1/arc-linux-uclibc/bin/ld +configure:4187: checking if the linker (/opt/gnutools/arc2.3-p0/uclibc-4.2.1/arc-linux-uclibc/bin/ld) is GNU ld +configure:4202: result: yes +configure:4207: checking for /opt/gnutools/arc2.3-p0/uclibc-4.2.1/arc-linux-uclibc/bin/ld option to reload object files +configure:4214: result: -r +configure:4232: checking for BSD-compatible nm +configure:4281: result: /opt/gnutools/arc2.3-p0/uclibc-4.2.1/bin/arc-linux-uclibc-nm -B +configure:4285: checking how to recognize dependent libraries +configure:4471: result: pass_all +configure:4716: checking how to run the C preprocessor +configure:4756: arc-linux-uclibc-gcc -E conftest.c +configure:4762: $? = 0 +configure:4793: arc-linux-uclibc-gcc -E conftest.c +conftest.c:11:28: error: ac_nonexistent.h: No such file or directory +configure:4799: $? = 1 +configure: failed program was: +| /* confdefs.h. */ +| #define PACKAGE_NAME "ntfs-3g" +| #define PACKAGE_TARNAME "ntfs-3g" +| #define PACKAGE_VERSION "2010.5.16" +| #define PACKAGE_STRING "ntfs-3g 2010.5.16" +| #define PACKAGE_BUGREPORT "ntfs-3g-devel@lists.sf.net" +| #define PACKAGE "ntfs-3g" +| #define VERSION "2010.5.16" +| #define _GNU_SOURCE 1 +| /* end confdefs.h. */ +| #include +configure:4832: result: arc-linux-uclibc-gcc -E +configure:4861: arc-linux-uclibc-gcc -E conftest.c +configure:4867: $? = 0 +configure:4898: arc-linux-uclibc-gcc -E conftest.c +conftest.c:11:28: error: ac_nonexistent.h: No such file or directory +configure:4904: $? = 1 +configure: failed program was: +| /* confdefs.h. */ +| #define PACKAGE_NAME "ntfs-3g" +| #define PACKAGE_TARNAME "ntfs-3g" +| #define PACKAGE_VERSION "2010.5.16" +| #define PACKAGE_STRING "ntfs-3g 2010.5.16" +| #define PACKAGE_BUGREPORT "ntfs-3g-devel@lists.sf.net" +| #define PACKAGE "ntfs-3g" +| #define VERSION "2010.5.16" +| #define _GNU_SOURCE 1 +| /* end confdefs.h. */ +| #include +configure:4942: checking for ANSI C header files +configure:4972: arc-linux-uclibc-gcc -c -mA7 -g conftest.c >&5 +configure:4978: $? = 0 +configure:5106: result: yes +configure:5130: checking for sys/types.h +configure:5151: arc-linux-uclibc-gcc -c -mA7 -g conftest.c >&5 +configure:5157: $? = 0 +configure:5173: result: yes +configure:5130: checking for sys/stat.h +configure:5151: arc-linux-uclibc-gcc -c -mA7 -g conftest.c >&5 +configure:5157: $? = 0 +configure:5173: result: yes +configure:5130: checking for stdlib.h +configure:5151: arc-linux-uclibc-gcc -c -mA7 -g conftest.c >&5 +configure:5157: $? = 0 +configure:5173: result: yes +configure:5130: checking for string.h +configure:5151: arc-linux-uclibc-gcc -c -mA7 -g conftest.c >&5 +configure:5157: $? = 0 +configure:5173: result: yes +configure:5130: checking for memory.h +configure:5151: arc-linux-uclibc-gcc -c -mA7 -g conftest.c >&5 +configure:5157: $? = 0 +configure:5173: result: yes +configure:5130: checking for strings.h +configure:5151: arc-linux-uclibc-gcc -c -mA7 -g conftest.c >&5 +configure:5157: $? = 0 +configure:5173: result: yes +configure:5130: checking for inttypes.h +configure:5151: arc-linux-uclibc-gcc -c -mA7 -g conftest.c >&5 +configure:5157: $? = 0 +configure:5173: result: yes +configure:5130: checking for stdint.h +configure:5151: arc-linux-uclibc-gcc -c -mA7 -g conftest.c >&5 +configure:5157: $? = 0 +configure:5173: result: yes +configure:5130: checking for unistd.h +configure:5151: arc-linux-uclibc-gcc -c -mA7 -g conftest.c >&5 +configure:5157: $? = 0 +configure:5173: result: yes +configure:5200: checking dlfcn.h usability +configure:5217: arc-linux-uclibc-gcc -c -mA7 -g conftest.c >&5 +configure:5223: $? = 0 +configure:5237: result: yes +configure:5241: checking dlfcn.h presence +configure:5256: arc-linux-uclibc-gcc -E conftest.c +configure:5262: $? = 0 +configure:5276: result: yes +configure:5309: checking for dlfcn.h +configure:5317: result: yes +configure:5344: checking for arc-linux-uclibc-g++ +configure:5360: found /opt/gnutools/arc2.3-p0/uclibc-4.2.1/bin/arc-linux-uclibc-g++ +configure:5371: result: arc-linux-uclibc-g++ +configure:5446: checking for C++ compiler version +configure:5453: arc-linux-uclibc-g++ --version >&5 +arc-linux-uclibc-g++ (GCC) 4.2.1 (ARC_2.3) +Copyright (C) 2007 Free Software Foundation, Inc. +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +configure:5456: $? = 0 +configure:5463: arc-linux-uclibc-g++ -v >&5 +Using built-in specs. +Target: arc-linux-uclibc +Configured with: ../src/configure --target=arc-linux-uclibc --prefix=/opt/gnutools/arc2.3-p0/uclibc-4.2.1 --with-headers=/opt/gnutools/arc2.3-p0/uclibc-4.2.1/arc-linux-uclibc/include --enable-shared --disable-multilib --without-newlib --enable-languages=c,c++ --with-cpu=arc700 --disable-c99 +Thread model: posix +gcc version 4.2.1 (ARC_2.3) +configure:5466: $? = 0 +configure:5473: arc-linux-uclibc-g++ -V >&5 +arc-linux-uclibc-g++: '-V' option must have argument +configure:5476: $? = 1 +configure:5479: checking whether we are using the GNU C++ compiler +configure:5508: arc-linux-uclibc-g++ -c conftest.cpp >&5 +configure:5514: $? = 0 +configure:5531: result: yes +configure:5536: checking whether arc-linux-uclibc-g++ accepts -g +configure:5566: arc-linux-uclibc-g++ -c -g conftest.cpp >&5 +configure:5572: $? = 0 +configure:5671: result: yes +configure:5696: checking dependency style of arc-linux-uclibc-g++ +configure:5787: result: gcc3 +configure:5812: checking how to run the C++ preprocessor +configure:5848: arc-linux-uclibc-g++ -E conftest.cpp +configure:5854: $? = 0 +configure:5885: arc-linux-uclibc-g++ -E conftest.cpp +conftest.cpp:22:28: error: ac_nonexistent.h: No such file or directory +configure:5891: $? = 1 +configure: failed program was: +| /* confdefs.h. */ +| #define PACKAGE_NAME "ntfs-3g" +| #define PACKAGE_TARNAME "ntfs-3g" +| #define PACKAGE_VERSION "2010.5.16" +| #define PACKAGE_STRING "ntfs-3g 2010.5.16" +| #define PACKAGE_BUGREPORT "ntfs-3g-devel@lists.sf.net" +| #define PACKAGE "ntfs-3g" +| #define VERSION "2010.5.16" +| #define _GNU_SOURCE 1 +| #define STDC_HEADERS 1 +| #define HAVE_SYS_TYPES_H 1 +| #define HAVE_SYS_STAT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_MEMORY_H 1 +| #define HAVE_STRINGS_H 1 +| #define HAVE_INTTYPES_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_UNISTD_H 1 +| #define HAVE_DLFCN_H 1 +| /* end confdefs.h. */ +| #include +configure:5924: result: arc-linux-uclibc-g++ -E +configure:5953: arc-linux-uclibc-g++ -E conftest.cpp +configure:5959: $? = 0 +configure:5990: arc-linux-uclibc-g++ -E conftest.cpp +conftest.cpp:22:28: error: ac_nonexistent.h: No such file or directory +configure:5996: $? = 1 +configure: failed program was: +| /* confdefs.h. */ +| #define PACKAGE_NAME "ntfs-3g" +| #define PACKAGE_TARNAME "ntfs-3g" +| #define PACKAGE_VERSION "2010.5.16" +| #define PACKAGE_STRING "ntfs-3g 2010.5.16" +| #define PACKAGE_BUGREPORT "ntfs-3g-devel@lists.sf.net" +| #define PACKAGE "ntfs-3g" +| #define VERSION "2010.5.16" +| #define _GNU_SOURCE 1 +| #define STDC_HEADERS 1 +| #define HAVE_SYS_TYPES_H 1 +| #define HAVE_SYS_STAT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_MEMORY_H 1 +| #define HAVE_STRINGS_H 1 +| #define HAVE_INTTYPES_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_UNISTD_H 1 +| #define HAVE_DLFCN_H 1 +| /* end confdefs.h. */ +| #include +configure:6045: checking for arc-linux-uclibc-g77 +configure:6075: result: no +configure:6045: checking for arc-linux-uclibc-xlf +configure:6075: result: no +configure:6045: checking for arc-linux-uclibc-f77 +configure:6075: result: no +configure:6045: checking for arc-linux-uclibc-frt +configure:6075: result: no +configure:6045: checking for arc-linux-uclibc-pgf77 +configure:6075: result: no +configure:6045: checking for arc-linux-uclibc-cf77 +configure:6075: result: no +configure:6045: checking for arc-linux-uclibc-fort77 +configure:6075: result: no +configure:6045: checking for arc-linux-uclibc-fl32 +configure:6075: result: no +configure:6045: checking for arc-linux-uclibc-af77 +configure:6075: result: no +configure:6045: checking for arc-linux-uclibc-xlf90 +configure:6075: result: no +configure:6045: checking for arc-linux-uclibc-f90 +configure:6075: result: no +configure:6045: checking for arc-linux-uclibc-pgf90 +configure:6075: result: no +configure:6045: checking for arc-linux-uclibc-pghpf +configure:6075: result: no +configure:6045: checking for arc-linux-uclibc-epcf90 +configure:6075: result: no +configure:6045: checking for arc-linux-uclibc-gfortran +configure:6075: result: no +configure:6045: checking for arc-linux-uclibc-g95 +configure:6075: result: no +configure:6045: checking for arc-linux-uclibc-xlf95 +configure:6075: result: no +configure:6045: checking for arc-linux-uclibc-f95 +configure:6075: result: no +configure:6045: checking for arc-linux-uclibc-fort +configure:6075: result: no +configure:6045: checking for arc-linux-uclibc-ifort +configure:6075: result: no +configure:6045: checking for arc-linux-uclibc-ifc +configure:6075: result: no +configure:6045: checking for arc-linux-uclibc-efc +configure:6075: result: no +configure:6045: checking for arc-linux-uclibc-pgf95 +configure:6075: result: no +configure:6045: checking for arc-linux-uclibc-lf95 +configure:6075: result: no +configure:6045: checking for arc-linux-uclibc-ftn +configure:6075: result: no +configure:6089: checking for g77 +configure:6119: result: no +configure:6089: checking for xlf +configure:6119: result: no +configure:6089: checking for f77 +configure:6119: result: no +configure:6089: checking for frt +configure:6119: result: no +configure:6089: checking for pgf77 +configure:6119: result: no +configure:6089: checking for cf77 +configure:6119: result: no +configure:6089: checking for fort77 +configure:6119: result: no +configure:6089: checking for fl32 +configure:6119: result: no +configure:6089: checking for af77 +configure:6119: result: no +configure:6089: checking for xlf90 +configure:6119: result: no +configure:6089: checking for f90 +configure:6119: result: no +configure:6089: checking for pgf90 +configure:6119: result: no +configure:6089: checking for pghpf +configure:6119: result: no +configure:6089: checking for epcf90 +configure:6119: result: no +configure:6089: checking for gfortran +configure:6119: result: no +configure:6089: checking for g95 +configure:6119: result: no +configure:6089: checking for xlf95 +configure:6119: result: no +configure:6089: checking for f95 +configure:6119: result: no +configure:6089: checking for fort +configure:6119: result: no +configure:6089: checking for ifort +configure:6119: result: no +configure:6089: checking for ifc +configure:6119: result: no +configure:6089: checking for efc +configure:6119: result: no +configure:6089: checking for pgf95 +configure:6119: result: no +configure:6089: checking for lf95 +configure:6119: result: no +configure:6089: checking for ftn +configure:6119: result: no +configure:6146: checking for Fortran 77 compiler version +configure:6153: --version >&5 +./configure: line 6154: --version: command not found +configure:6156: $? = 127 +configure:6163: -v >&5 +./configure: line 6164: -v: command not found +configure:6166: $? = 127 +configure:6173: -V >&5 +./configure: line 6174: -V: command not found +configure:6176: $? = 127 +configure:6184: checking whether we are using the GNU Fortran 77 compiler +configure:6203: -c conftest.F >&5 +./configure: line 6204: -c: command not found +configure:6209: $? = 127 +configure: failed program was: +| program main +| #ifndef __GNUC__ +| choke me +| #endif +| +| end +configure:6226: result: no +configure:6232: checking whether accepts -g +configure:6249: -c -g conftest.f >&5 +./configure: line 6250: -c: command not found +configure:6255: $? = 127 +configure: failed program was: +| program main +| +| end +configure:6271: result: no +configure:6300: checking the maximum length of command line arguments +configure:6412: result: 805306365 +configure:6424: checking command to parse /opt/gnutools/arc2.3-p0/uclibc-4.2.1/bin/arc-linux-uclibc-nm -B output from arc-linux-uclibc-gcc object +configure:6529: arc-linux-uclibc-gcc -c -mA7 -g conftest.c >&5 +configure:6532: $? = 0 +configure:6536: /opt/gnutools/arc2.3-p0/uclibc-4.2.1/bin/arc-linux-uclibc-nm -B conftest.o \| sed -n -e 's/^.*[ ]\([ABCDGIRSTW][ABCDGIRSTW]*\)[ ][ ]*\([_A-Za-z][_A-Za-z0-9]*\)$/\1 \2 \2/p' \> conftest.nm +configure:6539: $? = 0 +configure:6591: arc-linux-uclibc-gcc -o conftest -mA7 -g conftest.c conftstm.o >&5 +configure:6594: $? = 0 +configure:6632: result: ok +configure:6636: checking for objdir +configure:6651: result: .libs +configure:6703: checking for arc-linux-uclibc-ar +configure:6719: found /opt/gnutools/arc2.3-p0/uclibc-4.2.1/bin/arc-linux-uclibc-ar +configure:6730: result: arc-linux-uclibc-ar +configure:6799: checking for arc-linux-uclibc-ranlib +configure:6815: found /opt/gnutools/arc2.3-p0/uclibc-4.2.1/bin/arc-linux-uclibc-ranlib +configure:6826: result: arc-linux-uclibc-ranlib +configure:6895: checking for arc-linux-uclibc-strip +configure:6922: result: arc-linux-uclibc-strip +configure:7560: checking if arc-linux-uclibc-gcc supports -fno-rtti -fno-exceptions +configure:7578: arc-linux-uclibc-gcc -c -mA7 -g -fno-rtti -fno-exceptions conftest.c >&5 +cc1: warning: command line option "-fno-rtti" is valid for C++/ObjC++ but not for C +configure:7582: $? = 0 +configure:7595: result: no +configure:7610: checking for arc-linux-uclibc-gcc option to produce PIC +configure:7842: result: -fPIC +configure:7850: checking if arc-linux-uclibc-gcc PIC flag -fPIC works +configure:7868: arc-linux-uclibc-gcc -c -mA7 -g -fPIC -DPIC conftest.c >&5 +configure:7872: $? = 0 +configure:7885: result: yes +configure:7913: checking if arc-linux-uclibc-gcc static flag -static works +configure:7941: result: yes +configure:7951: checking if arc-linux-uclibc-gcc supports -c -o file.o +configure:7972: arc-linux-uclibc-gcc -c -mA7 -g -o out/conftest2.o conftest.c >&5 +configure:7976: $? = 0 +configure:7998: result: yes +configure:8024: checking whether the arc-linux-uclibc-gcc linker (/opt/gnutools/arc2.3-p0/uclibc-4.2.1/arc-linux-uclibc/bin/ld) supports shared libraries +configure:9004: result: yes +configure:9025: checking whether -lc should be explicitly linked in +configure:9030: arc-linux-uclibc-gcc -c -mA7 -g conftest.c >&5 +configure:9033: $? = 0 +configure:9048: arc-linux-uclibc-gcc -shared conftest.o -v -Wl,-soname -Wl,conftest -o conftest 2\>\&1 \| grep -lc \>/dev/null 2\>\&1 +configure:9051: $? = 0 +configure:9063: result: no +configure:9071: checking dynamic linker characteristics +configure:9673: result: GNU/Linux ld.so +configure:9697: checking how to hardcode library paths into programs +configure:9722: result: immediate +configure:9736: checking whether stripping libraries is possible +configure:9741: result: yes +configure:10543: checking if libtool supports shared libraries +configure:10545: result: yes +configure:10548: checking whether to build shared libraries +configure:10569: result: yes +configure:10572: checking whether to build static libraries +configure:10576: result: yes +configure:10670: creating libtool +configure:11263: checking for ld used by arc-linux-uclibc-g++ +configure:11330: result: /opt/gnutools/arc2.3-p0/uclibc-4.2.1/arc-linux-uclibc/bin/ld +configure:11339: checking if the linker (/opt/gnutools/arc2.3-p0/uclibc-4.2.1/arc-linux-uclibc/bin/ld) is GNU ld +configure:11354: result: yes +configure:11405: checking whether the arc-linux-uclibc-g++ linker (/opt/gnutools/arc2.3-p0/uclibc-4.2.1/arc-linux-uclibc/bin/ld) supports shared libraries +configure:12351: result: yes +configure:12368: arc-linux-uclibc-g++ -c -g -O2 conftest.cpp >&5 +configure:12371: $? = 0 +configure:12527: checking for arc-linux-uclibc-g++ option to produce PIC +configure:12811: result: -fPIC +configure:12819: checking if arc-linux-uclibc-g++ PIC flag -fPIC works +configure:12837: arc-linux-uclibc-g++ -c -g -O2 -fPIC -DPIC conftest.cpp >&5 +configure:12841: $? = 0 +configure:12854: result: yes +configure:12882: checking if arc-linux-uclibc-g++ static flag -static works +configure:12910: result: yes +configure:12920: checking if arc-linux-uclibc-g++ supports -c -o file.o +configure:12941: arc-linux-uclibc-g++ -c -g -O2 -o out/conftest2.o conftest.cpp >&5 +configure:12945: $? = 0 +configure:12967: result: yes +configure:12993: checking whether the arc-linux-uclibc-g++ linker (/opt/gnutools/arc2.3-p0/uclibc-4.2.1/arc-linux-uclibc/bin/ld) supports shared libraries +configure:13019: result: yes +configure:13086: checking dynamic linker characteristics +configure:13636: result: GNU/Linux ld.so +configure:13660: checking how to hardcode library paths into programs +configure:13685: result: immediate +configure:19910: checking for mv +configure:19928: found /bin/mv +configure:19940: result: /bin/mv +configure:19950: checking for rm +configure:19968: found /bin/rm +configure:19980: result: /bin/rm +configure:19990: checking for sed +configure:20020: result: /bin/sed +configure:20031: checking for ldconfig +configure:20049: found /sbin/ldconfig +configure:20062: result: /sbin/ldconfig +configure:20072: checking Windows OS +configure:20086: result: no +configure:20092: checking fuse compatibility +configure:20120: result: internal +configure:20149: checking for pthread_create in -lpthread +configure:20184: arc-linux-uclibc-gcc -o conftest -mA7 -g conftest.c -lpthread >&5 +configure:20190: $? = 0 +configure:20208: result: yes +configure:20481: checking for ANSI C header files +configure:20645: result: yes +configure:20715: checking ctype.h usability +configure:20732: arc-linux-uclibc-gcc -c -mA7 -g conftest.c >&5 +configure:20738: $? = 0 +configure:20752: result: yes +configure:20756: checking ctype.h presence +configure:20771: arc-linux-uclibc-gcc -E conftest.c +configure:20777: $? = 0 +configure:20791: result: yes +configure:20824: checking for ctype.h +configure:20832: result: yes +configure:20715: checking fcntl.h usability +configure:20732: arc-linux-uclibc-gcc -c -mA7 -g conftest.c >&5 +configure:20738: $? = 0 +configure:20752: result: yes +configure:20756: checking fcntl.h presence +configure:20771: arc-linux-uclibc-gcc -E conftest.c +configure:20777: $? = 0 +configure:20791: result: yes +configure:20824: checking for fcntl.h +configure:20832: result: yes +configure:20715: checking libgen.h usability +configure:20732: arc-linux-uclibc-gcc -c -mA7 -g conftest.c >&5 +configure:20738: $? = 0 +configure:20752: result: yes +configure:20756: checking libgen.h presence +configure:20771: arc-linux-uclibc-gcc -E conftest.c +configure:20777: $? = 0 +configure:20791: result: yes +configure:20824: checking for libgen.h +configure:20832: result: yes +configure:20715: checking libintl.h usability +configure:20732: arc-linux-uclibc-gcc -c -mA7 -g conftest.c >&5 +conftest.c:61:21: error: libintl.h: No such file or directory +configure:20738: $? = 1 +configure: failed program was: +| /* confdefs.h. */ +| #define PACKAGE_NAME "ntfs-3g" +| #define PACKAGE_TARNAME "ntfs-3g" +| #define PACKAGE_VERSION "2010.5.16" +| #define PACKAGE_STRING "ntfs-3g 2010.5.16" +| #define PACKAGE_BUGREPORT "ntfs-3g-devel@lists.sf.net" +| #define PACKAGE "ntfs-3g" +| #define VERSION "2010.5.16" +| #define _GNU_SOURCE 1 +| #define STDC_HEADERS 1 +| #define HAVE_SYS_TYPES_H 1 +| #define HAVE_SYS_STAT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_MEMORY_H 1 +| #define HAVE_STRINGS_H 1 +| #define HAVE_INTTYPES_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_UNISTD_H 1 +| #define HAVE_DLFCN_H 1 +| #define _REENTRANT 1 +| #define FUSE_INTERNAL 1 +| #define STDC_HEADERS 1 +| #define HAVE_CTYPE_H 1 +| #define HAVE_FCNTL_H 1 +| #define HAVE_LIBGEN_H 1 +| /* end confdefs.h. */ +| #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 +| #include +configure:20752: result: no +configure:20756: checking libintl.h presence +configure:20771: arc-linux-uclibc-gcc -E conftest.c +conftest.c:28:21: error: libintl.h: No such file or directory +configure:20777: $? = 1 +configure: failed program was: +| /* confdefs.h. */ +| #define PACKAGE_NAME "ntfs-3g" +| #define PACKAGE_TARNAME "ntfs-3g" +| #define PACKAGE_VERSION "2010.5.16" +| #define PACKAGE_STRING "ntfs-3g 2010.5.16" +| #define PACKAGE_BUGREPORT "ntfs-3g-devel@lists.sf.net" +| #define PACKAGE "ntfs-3g" +| #define VERSION "2010.5.16" +| #define _GNU_SOURCE 1 +| #define STDC_HEADERS 1 +| #define HAVE_SYS_TYPES_H 1 +| #define HAVE_SYS_STAT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_MEMORY_H 1 +| #define HAVE_STRINGS_H 1 +| #define HAVE_INTTYPES_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_UNISTD_H 1 +| #define HAVE_DLFCN_H 1 +| #define _REENTRANT 1 +| #define FUSE_INTERNAL 1 +| #define STDC_HEADERS 1 +| #define HAVE_CTYPE_H 1 +| #define HAVE_FCNTL_H 1 +| #define HAVE_LIBGEN_H 1 +| /* end confdefs.h. */ +| #include +configure:20791: result: no +configure:20824: checking for libintl.h +configure:20832: result: no +configure:20715: checking limits.h usability +configure:20732: arc-linux-uclibc-gcc -c -mA7 -g conftest.c >&5 +configure:20738: $? = 0 +configure:20752: result: yes +configure:20756: checking limits.h presence +configure:20771: arc-linux-uclibc-gcc -E conftest.c +configure:20777: $? = 0 +configure:20791: result: yes +configure:20824: checking for limits.h +configure:20832: result: yes +configure:20715: checking locale.h usability +configure:20732: arc-linux-uclibc-gcc -c -mA7 -g conftest.c >&5 +configure:20738: $? = 0 +configure:20752: result: yes +configure:20756: checking locale.h presence +configure:20771: arc-linux-uclibc-gcc -E conftest.c +configure:20777: $? = 0 +configure:20791: result: yes +configure:20824: checking for locale.h +configure:20832: result: yes +configure:20715: checking mntent.h usability +configure:20732: arc-linux-uclibc-gcc -c -mA7 -g conftest.c >&5 +configure:20738: $? = 0 +configure:20752: result: yes +configure:20756: checking mntent.h presence +configure:20771: arc-linux-uclibc-gcc -E conftest.c +configure:20777: $? = 0 +configure:20791: result: yes +configure:20824: checking for mntent.h +configure:20832: result: yes +configure:20715: checking stddef.h usability +configure:20732: arc-linux-uclibc-gcc -c -mA7 -g conftest.c >&5 +configure:20738: $? = 0 +configure:20752: result: yes +configure:20756: checking stddef.h presence +configure:20771: arc-linux-uclibc-gcc -E conftest.c +configure:20777: $? = 0 +configure:20791: result: yes +configure:20824: checking for stddef.h +configure:20832: result: yes +configure:20705: checking for stdint.h +configure:20711: result: yes +configure:20705: checking for stdlib.h +configure:20711: result: yes +configure:20715: checking stdio.h usability +configure:20732: arc-linux-uclibc-gcc -c -mA7 -g conftest.c >&5 +configure:20738: $? = 0 +configure:20752: result: yes +configure:20756: checking stdio.h presence +configure:20771: arc-linux-uclibc-gcc -E conftest.c +configure:20777: $? = 0 +configure:20791: result: yes +configure:20824: checking for stdio.h +configure:20832: result: yes +configure:20715: checking stdarg.h usability +configure:20732: arc-linux-uclibc-gcc -c -mA7 -g conftest.c >&5 +configure:20738: $? = 0 +configure:20752: result: yes +configure:20756: checking stdarg.h presence +configure:20771: arc-linux-uclibc-gcc -E conftest.c +configure:20777: $? = 0 +configure:20791: result: yes +configure:20824: checking for stdarg.h +configure:20832: result: yes +configure:20705: checking for string.h +configure:20711: result: yes +configure:20705: checking for strings.h +configure:20711: result: yes +configure:20715: checking errno.h usability +configure:20732: arc-linux-uclibc-gcc -c -mA7 -g conftest.c >&5 +configure:20738: $? = 0 +configure:20752: result: yes +configure:20756: checking errno.h presence +configure:20771: arc-linux-uclibc-gcc -E conftest.c +configure:20777: $? = 0 +configure:20791: result: yes +configure:20824: checking for errno.h +configure:20832: result: yes +configure:20715: checking time.h usability +configure:20732: arc-linux-uclibc-gcc -c -mA7 -g conftest.c >&5 +configure:20738: $? = 0 +configure:20752: result: yes +configure:20756: checking time.h presence +configure:20771: arc-linux-uclibc-gcc -E conftest.c +configure:20777: $? = 0 +configure:20791: result: yes +configure:20824: checking for time.h +configure:20832: result: yes +configure:20705: checking for unistd.h +configure:20711: result: yes +configure:20715: checking utime.h usability +configure:20732: arc-linux-uclibc-gcc -c -mA7 -g conftest.c >&5 +configure:20738: $? = 0 +configure:20752: result: yes +configure:20756: checking utime.h presence +configure:20771: arc-linux-uclibc-gcc -E conftest.c +configure:20777: $? = 0 +configure:20791: result: yes +configure:20824: checking for utime.h +configure:20832: result: yes +configure:20715: checking wchar.h usability +configure:20732: arc-linux-uclibc-gcc -c -mA7 -g conftest.c >&5 +configure:20738: $? = 0 +configure:20752: result: yes +configure:20756: checking wchar.h presence +configure:20771: arc-linux-uclibc-gcc -E conftest.c +configure:20777: $? = 0 +configure:20791: result: yes +configure:20824: checking for wchar.h +configure:20832: result: yes +configure:20715: checking getopt.h usability +configure:20732: arc-linux-uclibc-gcc -c -mA7 -g conftest.c >&5 +configure:20738: $? = 0 +configure:20752: result: yes +configure:20756: checking getopt.h presence +configure:20771: arc-linux-uclibc-gcc -E conftest.c +configure:20777: $? = 0 +configure:20791: result: yes +configure:20824: checking for getopt.h +configure:20832: result: yes +configure:20715: checking features.h usability +configure:20732: arc-linux-uclibc-gcc -c -mA7 -g conftest.c >&5 +configure:20738: $? = 0 +configure:20752: result: yes +configure:20756: checking features.h presence +configure:20771: arc-linux-uclibc-gcc -E conftest.c +configure:20777: $? = 0 +configure:20791: result: yes +configure:20824: checking for features.h +configure:20832: result: yes +configure:20715: checking endian.h usability +configure:20732: arc-linux-uclibc-gcc -c -mA7 -g conftest.c >&5 +configure:20738: $? = 0 +configure:20752: result: yes +configure:20756: checking endian.h presence +configure:20771: arc-linux-uclibc-gcc -E conftest.c +configure:20777: $? = 0 +configure:20791: result: yes +configure:20824: checking for endian.h +configure:20832: result: yes +configure:20715: checking byteswap.h usability +configure:20732: arc-linux-uclibc-gcc -c -mA7 -g conftest.c >&5 +configure:20738: $? = 0 +configure:20752: result: yes +configure:20756: checking byteswap.h presence +configure:20771: arc-linux-uclibc-gcc -E conftest.c +configure:20777: $? = 0 +configure:20791: result: yes +configure:20824: checking for byteswap.h +configure:20832: result: yes +configure:20715: checking sys/byteorder.h usability +configure:20732: arc-linux-uclibc-gcc -c -mA7 -g conftest.c >&5 +conftest.c:80:27: error: sys/byteorder.h: No such file or directory +configure:20738: $? = 1 +configure: failed program was: +| /* confdefs.h. */ +| #define PACKAGE_NAME "ntfs-3g" +| #define PACKAGE_TARNAME "ntfs-3g" +| #define PACKAGE_VERSION "2010.5.16" +| #define PACKAGE_STRING "ntfs-3g 2010.5.16" +| #define PACKAGE_BUGREPORT "ntfs-3g-devel@lists.sf.net" +| #define PACKAGE "ntfs-3g" +| #define VERSION "2010.5.16" +| #define _GNU_SOURCE 1 +| #define STDC_HEADERS 1 +| #define HAVE_SYS_TYPES_H 1 +| #define HAVE_SYS_STAT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_MEMORY_H 1 +| #define HAVE_STRINGS_H 1 +| #define HAVE_INTTYPES_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_UNISTD_H 1 +| #define HAVE_DLFCN_H 1 +| #define _REENTRANT 1 +| #define FUSE_INTERNAL 1 +| #define STDC_HEADERS 1 +| #define HAVE_CTYPE_H 1 +| #define HAVE_FCNTL_H 1 +| #define HAVE_LIBGEN_H 1 +| #define HAVE_LIMITS_H 1 +| #define HAVE_LOCALE_H 1 +| #define HAVE_MNTENT_H 1 +| #define HAVE_STDDEF_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STDIO_H 1 +| #define HAVE_STDARG_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_STRINGS_H 1 +| #define HAVE_ERRNO_H 1 +| #define HAVE_TIME_H 1 +| #define HAVE_UNISTD_H 1 +| #define HAVE_UTIME_H 1 +| #define HAVE_WCHAR_H 1 +| #define HAVE_GETOPT_H 1 +| #define HAVE_FEATURES_H 1 +| #define HAVE_ENDIAN_H 1 +| #define HAVE_BYTESWAP_H 1 +| /* end confdefs.h. */ +| #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 +| #include +configure:20752: result: no +configure:20756: checking sys/byteorder.h presence +configure:20771: arc-linux-uclibc-gcc -E conftest.c +conftest.c:47:27: error: sys/byteorder.h: No such file or directory +configure:20777: $? = 1 +configure: failed program was: +| /* confdefs.h. */ +| #define PACKAGE_NAME "ntfs-3g" +| #define PACKAGE_TARNAME "ntfs-3g" +| #define PACKAGE_VERSION "2010.5.16" +| #define PACKAGE_STRING "ntfs-3g 2010.5.16" +| #define PACKAGE_BUGREPORT "ntfs-3g-devel@lists.sf.net" +| #define PACKAGE "ntfs-3g" +| #define VERSION "2010.5.16" +| #define _GNU_SOURCE 1 +| #define STDC_HEADERS 1 +| #define HAVE_SYS_TYPES_H 1 +| #define HAVE_SYS_STAT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_MEMORY_H 1 +| #define HAVE_STRINGS_H 1 +| #define HAVE_INTTYPES_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_UNISTD_H 1 +| #define HAVE_DLFCN_H 1 +| #define _REENTRANT 1 +| #define FUSE_INTERNAL 1 +| #define STDC_HEADERS 1 +| #define HAVE_CTYPE_H 1 +| #define HAVE_FCNTL_H 1 +| #define HAVE_LIBGEN_H 1 +| #define HAVE_LIMITS_H 1 +| #define HAVE_LOCALE_H 1 +| #define HAVE_MNTENT_H 1 +| #define HAVE_STDDEF_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STDIO_H 1 +| #define HAVE_STDARG_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_STRINGS_H 1 +| #define HAVE_ERRNO_H 1 +| #define HAVE_TIME_H 1 +| #define HAVE_UNISTD_H 1 +| #define HAVE_UTIME_H 1 +| #define HAVE_WCHAR_H 1 +| #define HAVE_GETOPT_H 1 +| #define HAVE_FEATURES_H 1 +| #define HAVE_ENDIAN_H 1 +| #define HAVE_BYTESWAP_H 1 +| /* end confdefs.h. */ +| #include +configure:20791: result: no +configure:20824: checking for sys/byteorder.h +configure:20832: result: no +configure:20715: checking sys/endian.h usability +configure:20732: arc-linux-uclibc-gcc -c -mA7 -g conftest.c >&5 +conftest.c:80:24: error: sys/endian.h: No such file or directory +configure:20738: $? = 1 +configure: failed program was: +| /* confdefs.h. */ +| #define PACKAGE_NAME "ntfs-3g" +| #define PACKAGE_TARNAME "ntfs-3g" +| #define PACKAGE_VERSION "2010.5.16" +| #define PACKAGE_STRING "ntfs-3g 2010.5.16" +| #define PACKAGE_BUGREPORT "ntfs-3g-devel@lists.sf.net" +| #define PACKAGE "ntfs-3g" +| #define VERSION "2010.5.16" +| #define _GNU_SOURCE 1 +| #define STDC_HEADERS 1 +| #define HAVE_SYS_TYPES_H 1 +| #define HAVE_SYS_STAT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_MEMORY_H 1 +| #define HAVE_STRINGS_H 1 +| #define HAVE_INTTYPES_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_UNISTD_H 1 +| #define HAVE_DLFCN_H 1 +| #define _REENTRANT 1 +| #define FUSE_INTERNAL 1 +| #define STDC_HEADERS 1 +| #define HAVE_CTYPE_H 1 +| #define HAVE_FCNTL_H 1 +| #define HAVE_LIBGEN_H 1 +| #define HAVE_LIMITS_H 1 +| #define HAVE_LOCALE_H 1 +| #define HAVE_MNTENT_H 1 +| #define HAVE_STDDEF_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STDIO_H 1 +| #define HAVE_STDARG_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_STRINGS_H 1 +| #define HAVE_ERRNO_H 1 +| #define HAVE_TIME_H 1 +| #define HAVE_UNISTD_H 1 +| #define HAVE_UTIME_H 1 +| #define HAVE_WCHAR_H 1 +| #define HAVE_GETOPT_H 1 +| #define HAVE_FEATURES_H 1 +| #define HAVE_ENDIAN_H 1 +| #define HAVE_BYTESWAP_H 1 +| /* end confdefs.h. */ +| #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 +| #include +configure:20752: result: no +configure:20756: checking sys/endian.h presence +configure:20771: arc-linux-uclibc-gcc -E conftest.c +conftest.c:47:24: error: sys/endian.h: No such file or directory +configure:20777: $? = 1 +configure: failed program was: +| /* confdefs.h. */ +| #define PACKAGE_NAME "ntfs-3g" +| #define PACKAGE_TARNAME "ntfs-3g" +| #define PACKAGE_VERSION "2010.5.16" +| #define PACKAGE_STRING "ntfs-3g 2010.5.16" +| #define PACKAGE_BUGREPORT "ntfs-3g-devel@lists.sf.net" +| #define PACKAGE "ntfs-3g" +| #define VERSION "2010.5.16" +| #define _GNU_SOURCE 1 +| #define STDC_HEADERS 1 +| #define HAVE_SYS_TYPES_H 1 +| #define HAVE_SYS_STAT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_MEMORY_H 1 +| #define HAVE_STRINGS_H 1 +| #define HAVE_INTTYPES_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_UNISTD_H 1 +| #define HAVE_DLFCN_H 1 +| #define _REENTRANT 1 +| #define FUSE_INTERNAL 1 +| #define STDC_HEADERS 1 +| #define HAVE_CTYPE_H 1 +| #define HAVE_FCNTL_H 1 +| #define HAVE_LIBGEN_H 1 +| #define HAVE_LIMITS_H 1 +| #define HAVE_LOCALE_H 1 +| #define HAVE_MNTENT_H 1 +| #define HAVE_STDDEF_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STDIO_H 1 +| #define HAVE_STDARG_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_STRINGS_H 1 +| #define HAVE_ERRNO_H 1 +| #define HAVE_TIME_H 1 +| #define HAVE_UNISTD_H 1 +| #define HAVE_UTIME_H 1 +| #define HAVE_WCHAR_H 1 +| #define HAVE_GETOPT_H 1 +| #define HAVE_FEATURES_H 1 +| #define HAVE_ENDIAN_H 1 +| #define HAVE_BYTESWAP_H 1 +| /* end confdefs.h. */ +| #include +configure:20791: result: no +configure:20824: checking for sys/endian.h +configure:20832: result: no +configure:20715: checking sys/param.h usability +configure:20732: arc-linux-uclibc-gcc -c -mA7 -g conftest.c >&5 +configure:20738: $? = 0 +configure:20752: result: yes +configure:20756: checking sys/param.h presence +configure:20771: arc-linux-uclibc-gcc -E conftest.c +configure:20777: $? = 0 +configure:20791: result: yes +configure:20824: checking for sys/param.h +configure:20832: result: yes +configure:20715: checking sys/ioctl.h usability +configure:20732: arc-linux-uclibc-gcc -c -mA7 -g conftest.c >&5 +configure:20738: $? = 0 +configure:20752: result: yes +configure:20756: checking sys/ioctl.h presence +configure:20771: arc-linux-uclibc-gcc -E conftest.c +configure:20777: $? = 0 +configure:20791: result: yes +configure:20824: checking for sys/ioctl.h +configure:20832: result: yes +configure:20715: checking sys/mkdev.h usability +configure:20732: arc-linux-uclibc-gcc -c -mA7 -g conftest.c >&5 +conftest.c:82:23: error: sys/mkdev.h: No such file or directory +configure:20738: $? = 1 +configure: failed program was: +| /* confdefs.h. */ +| #define PACKAGE_NAME "ntfs-3g" +| #define PACKAGE_TARNAME "ntfs-3g" +| #define PACKAGE_VERSION "2010.5.16" +| #define PACKAGE_STRING "ntfs-3g 2010.5.16" +| #define PACKAGE_BUGREPORT "ntfs-3g-devel@lists.sf.net" +| #define PACKAGE "ntfs-3g" +| #define VERSION "2010.5.16" +| #define _GNU_SOURCE 1 +| #define STDC_HEADERS 1 +| #define HAVE_SYS_TYPES_H 1 +| #define HAVE_SYS_STAT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_MEMORY_H 1 +| #define HAVE_STRINGS_H 1 +| #define HAVE_INTTYPES_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_UNISTD_H 1 +| #define HAVE_DLFCN_H 1 +| #define _REENTRANT 1 +| #define FUSE_INTERNAL 1 +| #define STDC_HEADERS 1 +| #define HAVE_CTYPE_H 1 +| #define HAVE_FCNTL_H 1 +| #define HAVE_LIBGEN_H 1 +| #define HAVE_LIMITS_H 1 +| #define HAVE_LOCALE_H 1 +| #define HAVE_MNTENT_H 1 +| #define HAVE_STDDEF_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STDIO_H 1 +| #define HAVE_STDARG_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_STRINGS_H 1 +| #define HAVE_ERRNO_H 1 +| #define HAVE_TIME_H 1 +| #define HAVE_UNISTD_H 1 +| #define HAVE_UTIME_H 1 +| #define HAVE_WCHAR_H 1 +| #define HAVE_GETOPT_H 1 +| #define HAVE_FEATURES_H 1 +| #define HAVE_ENDIAN_H 1 +| #define HAVE_BYTESWAP_H 1 +| #define HAVE_SYS_PARAM_H 1 +| #define HAVE_SYS_IOCTL_H 1 +| /* end confdefs.h. */ +| #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 +| #include +configure:20752: result: no +configure:20756: checking sys/mkdev.h presence +configure:20771: arc-linux-uclibc-gcc -E conftest.c +conftest.c:49:23: error: sys/mkdev.h: No such file or directory +configure:20777: $? = 1 +configure: failed program was: +| /* confdefs.h. */ +| #define PACKAGE_NAME "ntfs-3g" +| #define PACKAGE_TARNAME "ntfs-3g" +| #define PACKAGE_VERSION "2010.5.16" +| #define PACKAGE_STRING "ntfs-3g 2010.5.16" +| #define PACKAGE_BUGREPORT "ntfs-3g-devel@lists.sf.net" +| #define PACKAGE "ntfs-3g" +| #define VERSION "2010.5.16" +| #define _GNU_SOURCE 1 +| #define STDC_HEADERS 1 +| #define HAVE_SYS_TYPES_H 1 +| #define HAVE_SYS_STAT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_MEMORY_H 1 +| #define HAVE_STRINGS_H 1 +| #define HAVE_INTTYPES_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_UNISTD_H 1 +| #define HAVE_DLFCN_H 1 +| #define _REENTRANT 1 +| #define FUSE_INTERNAL 1 +| #define STDC_HEADERS 1 +| #define HAVE_CTYPE_H 1 +| #define HAVE_FCNTL_H 1 +| #define HAVE_LIBGEN_H 1 +| #define HAVE_LIMITS_H 1 +| #define HAVE_LOCALE_H 1 +| #define HAVE_MNTENT_H 1 +| #define HAVE_STDDEF_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STDIO_H 1 +| #define HAVE_STDARG_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_STRINGS_H 1 +| #define HAVE_ERRNO_H 1 +| #define HAVE_TIME_H 1 +| #define HAVE_UNISTD_H 1 +| #define HAVE_UTIME_H 1 +| #define HAVE_WCHAR_H 1 +| #define HAVE_GETOPT_H 1 +| #define HAVE_FEATURES_H 1 +| #define HAVE_ENDIAN_H 1 +| #define HAVE_BYTESWAP_H 1 +| #define HAVE_SYS_PARAM_H 1 +| #define HAVE_SYS_IOCTL_H 1 +| /* end confdefs.h. */ +| #include +configure:20791: result: no +configure:20824: checking for sys/mkdev.h +configure:20832: result: no +configure:20715: checking sys/mount.h usability +configure:20732: arc-linux-uclibc-gcc -c -mA7 -g conftest.c >&5 +configure:20738: $? = 0 +configure:20752: result: yes +configure:20756: checking sys/mount.h presence +configure:20771: arc-linux-uclibc-gcc -E conftest.c +configure:20777: $? = 0 +configure:20791: result: yes +configure:20824: checking for sys/mount.h +configure:20832: result: yes +configure:20705: checking for sys/stat.h +configure:20711: result: yes +configure:20705: checking for sys/types.h +configure:20711: result: yes +configure:20715: checking sys/vfs.h usability +configure:20732: arc-linux-uclibc-gcc -c -mA7 -g conftest.c >&5 +configure:20738: $? = 0 +configure:20752: result: yes +configure:20756: checking sys/vfs.h presence +configure:20771: arc-linux-uclibc-gcc -E conftest.c +configure:20777: $? = 0 +configure:20791: result: yes +configure:20824: checking for sys/vfs.h +configure:20832: result: yes +configure:20715: checking sys/statvfs.h usability +configure:20732: arc-linux-uclibc-gcc -c -mA7 -g conftest.c >&5 +configure:20738: $? = 0 +configure:20752: result: yes +configure:20756: checking sys/statvfs.h presence +configure:20771: arc-linux-uclibc-gcc -E conftest.c +configure:20777: $? = 0 +configure:20791: result: yes +configure:20824: checking for sys/statvfs.h +configure:20832: result: yes +configure:20715: checking sys/sysmacros.h usability +configure:20732: arc-linux-uclibc-gcc -c -mA7 -g conftest.c >&5 +configure:20738: $? = 0 +configure:20752: result: yes +configure:20756: checking sys/sysmacros.h presence +configure:20771: arc-linux-uclibc-gcc -E conftest.c +configure:20777: $? = 0 +configure:20791: result: yes +configure:20824: checking for sys/sysmacros.h +configure:20832: result: yes +configure:20715: checking linux/major.h usability +configure:20732: arc-linux-uclibc-gcc -c -mA7 -g conftest.c >&5 +configure:20738: $? = 0 +configure:20752: result: yes +configure:20756: checking linux/major.h presence +configure:20771: arc-linux-uclibc-gcc -E conftest.c +configure:20777: $? = 0 +configure:20791: result: yes +configure:20824: checking for linux/major.h +configure:20832: result: yes +configure:20715: checking linux/fd.h usability +configure:20732: arc-linux-uclibc-gcc -c -mA7 -g conftest.c >&5 +configure:20738: $? = 0 +configure:20752: result: yes +configure:20756: checking linux/fd.h presence +configure:20771: arc-linux-uclibc-gcc -E conftest.c +configure:20777: $? = 0 +configure:20791: result: yes +configure:20824: checking for linux/fd.h +configure:20832: result: yes +configure:20715: checking linux/hdreg.h usability +configure:20732: arc-linux-uclibc-gcc -c -mA7 -g conftest.c >&5 +configure:20738: $? = 0 +configure:20752: result: yes +configure:20756: checking linux/hdreg.h presence +configure:20771: arc-linux-uclibc-gcc -E conftest.c +configure:20777: $? = 0 +configure:20791: result: yes +configure:20824: checking for linux/hdreg.h +configure:20832: result: yes +configure:20715: checking machine/endian.h usability +configure:20732: arc-linux-uclibc-gcc -c -mA7 -g conftest.c >&5 +conftest.c:91:28: error: machine/endian.h: No such file or directory +configure:20738: $? = 1 +configure: failed program was: +| /* confdefs.h. */ +| #define PACKAGE_NAME "ntfs-3g" +| #define PACKAGE_TARNAME "ntfs-3g" +| #define PACKAGE_VERSION "2010.5.16" +| #define PACKAGE_STRING "ntfs-3g 2010.5.16" +| #define PACKAGE_BUGREPORT "ntfs-3g-devel@lists.sf.net" +| #define PACKAGE "ntfs-3g" +| #define VERSION "2010.5.16" +| #define _GNU_SOURCE 1 +| #define STDC_HEADERS 1 +| #define HAVE_SYS_TYPES_H 1 +| #define HAVE_SYS_STAT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_MEMORY_H 1 +| #define HAVE_STRINGS_H 1 +| #define HAVE_INTTYPES_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_UNISTD_H 1 +| #define HAVE_DLFCN_H 1 +| #define _REENTRANT 1 +| #define FUSE_INTERNAL 1 +| #define STDC_HEADERS 1 +| #define HAVE_CTYPE_H 1 +| #define HAVE_FCNTL_H 1 +| #define HAVE_LIBGEN_H 1 +| #define HAVE_LIMITS_H 1 +| #define HAVE_LOCALE_H 1 +| #define HAVE_MNTENT_H 1 +| #define HAVE_STDDEF_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STDIO_H 1 +| #define HAVE_STDARG_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_STRINGS_H 1 +| #define HAVE_ERRNO_H 1 +| #define HAVE_TIME_H 1 +| #define HAVE_UNISTD_H 1 +| #define HAVE_UTIME_H 1 +| #define HAVE_WCHAR_H 1 +| #define HAVE_GETOPT_H 1 +| #define HAVE_FEATURES_H 1 +| #define HAVE_ENDIAN_H 1 +| #define HAVE_BYTESWAP_H 1 +| #define HAVE_SYS_PARAM_H 1 +| #define HAVE_SYS_IOCTL_H 1 +| #define HAVE_SYS_MOUNT_H 1 +| #define HAVE_SYS_STAT_H 1 +| #define HAVE_SYS_TYPES_H 1 +| #define HAVE_SYS_VFS_H 1 +| #define HAVE_SYS_STATVFS_H 1 +| #define HAVE_SYS_SYSMACROS_H 1 +| #define HAVE_LINUX_MAJOR_H 1 +| #define HAVE_LINUX_FD_H 1 +| #define HAVE_LINUX_HDREG_H 1 +| /* end confdefs.h. */ +| #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 +| #include +configure:20752: result: no +configure:20756: checking machine/endian.h presence +configure:20771: arc-linux-uclibc-gcc -E conftest.c +conftest.c:58:28: error: machine/endian.h: No such file or directory +configure:20777: $? = 1 +configure: failed program was: +| /* confdefs.h. */ +| #define PACKAGE_NAME "ntfs-3g" +| #define PACKAGE_TARNAME "ntfs-3g" +| #define PACKAGE_VERSION "2010.5.16" +| #define PACKAGE_STRING "ntfs-3g 2010.5.16" +| #define PACKAGE_BUGREPORT "ntfs-3g-devel@lists.sf.net" +| #define PACKAGE "ntfs-3g" +| #define VERSION "2010.5.16" +| #define _GNU_SOURCE 1 +| #define STDC_HEADERS 1 +| #define HAVE_SYS_TYPES_H 1 +| #define HAVE_SYS_STAT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_MEMORY_H 1 +| #define HAVE_STRINGS_H 1 +| #define HAVE_INTTYPES_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_UNISTD_H 1 +| #define HAVE_DLFCN_H 1 +| #define _REENTRANT 1 +| #define FUSE_INTERNAL 1 +| #define STDC_HEADERS 1 +| #define HAVE_CTYPE_H 1 +| #define HAVE_FCNTL_H 1 +| #define HAVE_LIBGEN_H 1 +| #define HAVE_LIMITS_H 1 +| #define HAVE_LOCALE_H 1 +| #define HAVE_MNTENT_H 1 +| #define HAVE_STDDEF_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STDIO_H 1 +| #define HAVE_STDARG_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_STRINGS_H 1 +| #define HAVE_ERRNO_H 1 +| #define HAVE_TIME_H 1 +| #define HAVE_UNISTD_H 1 +| #define HAVE_UTIME_H 1 +| #define HAVE_WCHAR_H 1 +| #define HAVE_GETOPT_H 1 +| #define HAVE_FEATURES_H 1 +| #define HAVE_ENDIAN_H 1 +| #define HAVE_BYTESWAP_H 1 +| #define HAVE_SYS_PARAM_H 1 +| #define HAVE_SYS_IOCTL_H 1 +| #define HAVE_SYS_MOUNT_H 1 +| #define HAVE_SYS_STAT_H 1 +| #define HAVE_SYS_TYPES_H 1 +| #define HAVE_SYS_VFS_H 1 +| #define HAVE_SYS_STATVFS_H 1 +| #define HAVE_SYS_SYSMACROS_H 1 +| #define HAVE_LINUX_MAJOR_H 1 +| #define HAVE_LINUX_FD_H 1 +| #define HAVE_LINUX_HDREG_H 1 +| /* end confdefs.h. */ +| #include +configure:20791: result: no +configure:20824: checking for machine/endian.h +configure:20832: result: no +configure:20715: checking windows.h usability +configure:20732: arc-linux-uclibc-gcc -c -mA7 -g conftest.c >&5 +conftest.c:91:21: error: windows.h: No such file or directory +configure:20738: $? = 1 +configure: failed program was: +| /* confdefs.h. */ +| #define PACKAGE_NAME "ntfs-3g" +| #define PACKAGE_TARNAME "ntfs-3g" +| #define PACKAGE_VERSION "2010.5.16" +| #define PACKAGE_STRING "ntfs-3g 2010.5.16" +| #define PACKAGE_BUGREPORT "ntfs-3g-devel@lists.sf.net" +| #define PACKAGE "ntfs-3g" +| #define VERSION "2010.5.16" +| #define _GNU_SOURCE 1 +| #define STDC_HEADERS 1 +| #define HAVE_SYS_TYPES_H 1 +| #define HAVE_SYS_STAT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_MEMORY_H 1 +| #define HAVE_STRINGS_H 1 +| #define HAVE_INTTYPES_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_UNISTD_H 1 +| #define HAVE_DLFCN_H 1 +| #define _REENTRANT 1 +| #define FUSE_INTERNAL 1 +| #define STDC_HEADERS 1 +| #define HAVE_CTYPE_H 1 +| #define HAVE_FCNTL_H 1 +| #define HAVE_LIBGEN_H 1 +| #define HAVE_LIMITS_H 1 +| #define HAVE_LOCALE_H 1 +| #define HAVE_MNTENT_H 1 +| #define HAVE_STDDEF_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STDIO_H 1 +| #define HAVE_STDARG_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_STRINGS_H 1 +| #define HAVE_ERRNO_H 1 +| #define HAVE_TIME_H 1 +| #define HAVE_UNISTD_H 1 +| #define HAVE_UTIME_H 1 +| #define HAVE_WCHAR_H 1 +| #define HAVE_GETOPT_H 1 +| #define HAVE_FEATURES_H 1 +| #define HAVE_ENDIAN_H 1 +| #define HAVE_BYTESWAP_H 1 +| #define HAVE_SYS_PARAM_H 1 +| #define HAVE_SYS_IOCTL_H 1 +| #define HAVE_SYS_MOUNT_H 1 +| #define HAVE_SYS_STAT_H 1 +| #define HAVE_SYS_TYPES_H 1 +| #define HAVE_SYS_VFS_H 1 +| #define HAVE_SYS_STATVFS_H 1 +| #define HAVE_SYS_SYSMACROS_H 1 +| #define HAVE_LINUX_MAJOR_H 1 +| #define HAVE_LINUX_FD_H 1 +| #define HAVE_LINUX_HDREG_H 1 +| /* end confdefs.h. */ +| #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 +| #include +configure:20752: result: no +configure:20756: checking windows.h presence +configure:20771: arc-linux-uclibc-gcc -E conftest.c +conftest.c:58:21: error: windows.h: No such file or directory +configure:20777: $? = 1 +configure: failed program was: +| /* confdefs.h. */ +| #define PACKAGE_NAME "ntfs-3g" +| #define PACKAGE_TARNAME "ntfs-3g" +| #define PACKAGE_VERSION "2010.5.16" +| #define PACKAGE_STRING "ntfs-3g 2010.5.16" +| #define PACKAGE_BUGREPORT "ntfs-3g-devel@lists.sf.net" +| #define PACKAGE "ntfs-3g" +| #define VERSION "2010.5.16" +| #define _GNU_SOURCE 1 +| #define STDC_HEADERS 1 +| #define HAVE_SYS_TYPES_H 1 +| #define HAVE_SYS_STAT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_MEMORY_H 1 +| #define HAVE_STRINGS_H 1 +| #define HAVE_INTTYPES_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_UNISTD_H 1 +| #define HAVE_DLFCN_H 1 +| #define _REENTRANT 1 +| #define FUSE_INTERNAL 1 +| #define STDC_HEADERS 1 +| #define HAVE_CTYPE_H 1 +| #define HAVE_FCNTL_H 1 +| #define HAVE_LIBGEN_H 1 +| #define HAVE_LIMITS_H 1 +| #define HAVE_LOCALE_H 1 +| #define HAVE_MNTENT_H 1 +| #define HAVE_STDDEF_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STDIO_H 1 +| #define HAVE_STDARG_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_STRINGS_H 1 +| #define HAVE_ERRNO_H 1 +| #define HAVE_TIME_H 1 +| #define HAVE_UNISTD_H 1 +| #define HAVE_UTIME_H 1 +| #define HAVE_WCHAR_H 1 +| #define HAVE_GETOPT_H 1 +| #define HAVE_FEATURES_H 1 +| #define HAVE_ENDIAN_H 1 +| #define HAVE_BYTESWAP_H 1 +| #define HAVE_SYS_PARAM_H 1 +| #define HAVE_SYS_IOCTL_H 1 +| #define HAVE_SYS_MOUNT_H 1 +| #define HAVE_SYS_STAT_H 1 +| #define HAVE_SYS_TYPES_H 1 +| #define HAVE_SYS_VFS_H 1 +| #define HAVE_SYS_STATVFS_H 1 +| #define HAVE_SYS_SYSMACROS_H 1 +| #define HAVE_LINUX_MAJOR_H 1 +| #define HAVE_LINUX_FD_H 1 +| #define HAVE_LINUX_HDREG_H 1 +| /* end confdefs.h. */ +| #include +configure:20791: result: no +configure:20824: checking for windows.h +configure:20832: result: no +configure:20715: checking syslog.h usability +configure:20732: arc-linux-uclibc-gcc -c -mA7 -g conftest.c >&5 +configure:20738: $? = 0 +configure:20752: result: yes +configure:20756: checking syslog.h presence +configure:20771: arc-linux-uclibc-gcc -E conftest.c +configure:20777: $? = 0 +configure:20791: result: yes +configure:20824: checking for syslog.h +configure:20832: result: yes +configure:20847: checking for stdbool.h that conforms to C99 +configure:20940: arc-linux-uclibc-gcc -c -mA7 -g conftest.c >&5 +configure:20946: $? = 0 +configure:20961: result: yes +configure:20963: checking for _Bool +configure:20993: arc-linux-uclibc-gcc -c -mA7 -g conftest.c >&5 +configure:20999: $? = 0 +configure:21014: result: yes +configure:21033: checking whether byte ordering is bigendian +configure:21066: arc-linux-uclibc-gcc -c -mA7 -g conftest.c >&5 +configure:21072: $? = 0 +configure:21104: arc-linux-uclibc-gcc -c -mA7 -g conftest.c >&5 +conftest.c: In function 'main': +conftest.c:68: error: 'not' undeclared (first use in this function) +conftest.c:68: error: (Each undeclared identifier is reported only once +conftest.c:68: error: for each function it appears in.) +conftest.c:68: error: expected ';' before 'big' +configure:21110: $? = 1 +configure: failed program was: +| /* confdefs.h. */ +| #define PACKAGE_NAME "ntfs-3g" +| #define PACKAGE_TARNAME "ntfs-3g" +| #define PACKAGE_VERSION "2010.5.16" +| #define PACKAGE_STRING "ntfs-3g 2010.5.16" +| #define PACKAGE_BUGREPORT "ntfs-3g-devel@lists.sf.net" +| #define PACKAGE "ntfs-3g" +| #define VERSION "2010.5.16" +| #define _GNU_SOURCE 1 +| #define STDC_HEADERS 1 +| #define HAVE_SYS_TYPES_H 1 +| #define HAVE_SYS_STAT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_MEMORY_H 1 +| #define HAVE_STRINGS_H 1 +| #define HAVE_INTTYPES_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_UNISTD_H 1 +| #define HAVE_DLFCN_H 1 +| #define _REENTRANT 1 +| #define FUSE_INTERNAL 1 +| #define STDC_HEADERS 1 +| #define HAVE_CTYPE_H 1 +| #define HAVE_FCNTL_H 1 +| #define HAVE_LIBGEN_H 1 +| #define HAVE_LIMITS_H 1 +| #define HAVE_LOCALE_H 1 +| #define HAVE_MNTENT_H 1 +| #define HAVE_STDDEF_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STDIO_H 1 +| #define HAVE_STDARG_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_STRINGS_H 1 +| #define HAVE_ERRNO_H 1 +| #define HAVE_TIME_H 1 +| #define HAVE_UNISTD_H 1 +| #define HAVE_UTIME_H 1 +| #define HAVE_WCHAR_H 1 +| #define HAVE_GETOPT_H 1 +| #define HAVE_FEATURES_H 1 +| #define HAVE_ENDIAN_H 1 +| #define HAVE_BYTESWAP_H 1 +| #define HAVE_SYS_PARAM_H 1 +| #define HAVE_SYS_IOCTL_H 1 +| #define HAVE_SYS_MOUNT_H 1 +| #define HAVE_SYS_STAT_H 1 +| #define HAVE_SYS_TYPES_H 1 +| #define HAVE_SYS_VFS_H 1 +| #define HAVE_SYS_STATVFS_H 1 +| #define HAVE_SYS_SYSMACROS_H 1 +| #define HAVE_LINUX_MAJOR_H 1 +| #define HAVE_LINUX_FD_H 1 +| #define HAVE_LINUX_HDREG_H 1 +| #define HAVE_SYSLOG_H 1 +| #define HAVE__BOOL 1 +| #define HAVE_STDBOOL_H 1 +| /* end confdefs.h. */ +| #include +| #include +| +| int +| main () +| { +| #if BYTE_ORDER != BIG_ENDIAN +| not big endian +| #endif +| +| ; +| return 0; +| } +configure:21250: result: no +configure:21276: checking for inline +configure:21302: arc-linux-uclibc-gcc -c -mA7 -g conftest.c >&5 +configure:21308: $? = 0 +configure:21326: result: inline +configure:21345: checking for off_t +configure:21375: arc-linux-uclibc-gcc -c -mA7 -g conftest.c >&5 +configure:21381: $? = 0 +configure:21396: result: yes +configure:21408: checking for size_t +configure:21438: arc-linux-uclibc-gcc -c -mA7 -g conftest.c >&5 +configure:21444: $? = 0 +configure:21459: result: yes +configure:21471: checking for struct stat.st_blocks +configure:21499: arc-linux-uclibc-gcc -c -mA7 -g conftest.c >&5 +configure:21505: $? = 0 +configure:21562: result: yes +configure:21585: checking for struct stat.st_rdev +configure:21613: arc-linux-uclibc-gcc -c -mA7 -g conftest.c >&5 +configure:21619: $? = 0 +configure:21676: result: yes +configure:21687: checking for struct stat.st_atim +configure:21715: arc-linux-uclibc-gcc -c -mA7 -g conftest.c >&5 +conftest.c: In function 'main': +conftest.c:102: error: 'struct stat' has no member named 'st_atim' +configure:21721: $? = 1 +configure: failed program was: +| /* confdefs.h. */ +| #define PACKAGE_NAME "ntfs-3g" +| #define PACKAGE_TARNAME "ntfs-3g" +| #define PACKAGE_VERSION "2010.5.16" +| #define PACKAGE_STRING "ntfs-3g 2010.5.16" +| #define PACKAGE_BUGREPORT "ntfs-3g-devel@lists.sf.net" +| #define PACKAGE "ntfs-3g" +| #define VERSION "2010.5.16" +| #define _GNU_SOURCE 1 +| #define STDC_HEADERS 1 +| #define HAVE_SYS_TYPES_H 1 +| #define HAVE_SYS_STAT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_MEMORY_H 1 +| #define HAVE_STRINGS_H 1 +| #define HAVE_INTTYPES_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_UNISTD_H 1 +| #define HAVE_DLFCN_H 1 +| #define _REENTRANT 1 +| #define FUSE_INTERNAL 1 +| #define STDC_HEADERS 1 +| #define HAVE_CTYPE_H 1 +| #define HAVE_FCNTL_H 1 +| #define HAVE_LIBGEN_H 1 +| #define HAVE_LIMITS_H 1 +| #define HAVE_LOCALE_H 1 +| #define HAVE_MNTENT_H 1 +| #define HAVE_STDDEF_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STDIO_H 1 +| #define HAVE_STDARG_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_STRINGS_H 1 +| #define HAVE_ERRNO_H 1 +| #define HAVE_TIME_H 1 +| #define HAVE_UNISTD_H 1 +| #define HAVE_UTIME_H 1 +| #define HAVE_WCHAR_H 1 +| #define HAVE_GETOPT_H 1 +| #define HAVE_FEATURES_H 1 +| #define HAVE_ENDIAN_H 1 +| #define HAVE_BYTESWAP_H 1 +| #define HAVE_SYS_PARAM_H 1 +| #define HAVE_SYS_IOCTL_H 1 +| #define HAVE_SYS_MOUNT_H 1 +| #define HAVE_SYS_STAT_H 1 +| #define HAVE_SYS_TYPES_H 1 +| #define HAVE_SYS_VFS_H 1 +| #define HAVE_SYS_STATVFS_H 1 +| #define HAVE_SYS_SYSMACROS_H 1 +| #define HAVE_LINUX_MAJOR_H 1 +| #define HAVE_LINUX_FD_H 1 +| #define HAVE_LINUX_HDREG_H 1 +| #define HAVE_SYSLOG_H 1 +| #define HAVE__BOOL 1 +| #define HAVE_STDBOOL_H 1 +| #define WORDS_LITTLEENDIAN 1 +| #define HAVE_STRUCT_STAT_ST_BLOCKS 1 +| #define HAVE_ST_BLOCKS 1 +| #define HAVE_STRUCT_STAT_ST_RDEV 1 +| /* end confdefs.h. */ +| #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 +| int +| main () +| { +| static struct stat ac_aggr; +| if (ac_aggr.st_atim) +| return 0; +| ; +| return 0; +| } +configure:21754: arc-linux-uclibc-gcc -c -mA7 -g conftest.c >&5 +conftest.c: In function 'main': +conftest.c:102: error: 'struct stat' has no member named 'st_atim' +configure:21760: $? = 1 +configure: failed program was: +| /* confdefs.h. */ +| #define PACKAGE_NAME "ntfs-3g" +| #define PACKAGE_TARNAME "ntfs-3g" +| #define PACKAGE_VERSION "2010.5.16" +| #define PACKAGE_STRING "ntfs-3g 2010.5.16" +| #define PACKAGE_BUGREPORT "ntfs-3g-devel@lists.sf.net" +| #define PACKAGE "ntfs-3g" +| #define VERSION "2010.5.16" +| #define _GNU_SOURCE 1 +| #define STDC_HEADERS 1 +| #define HAVE_SYS_TYPES_H 1 +| #define HAVE_SYS_STAT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_MEMORY_H 1 +| #define HAVE_STRINGS_H 1 +| #define HAVE_INTTYPES_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_UNISTD_H 1 +| #define HAVE_DLFCN_H 1 +| #define _REENTRANT 1 +| #define FUSE_INTERNAL 1 +| #define STDC_HEADERS 1 +| #define HAVE_CTYPE_H 1 +| #define HAVE_FCNTL_H 1 +| #define HAVE_LIBGEN_H 1 +| #define HAVE_LIMITS_H 1 +| #define HAVE_LOCALE_H 1 +| #define HAVE_MNTENT_H 1 +| #define HAVE_STDDEF_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STDIO_H 1 +| #define HAVE_STDARG_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_STRINGS_H 1 +| #define HAVE_ERRNO_H 1 +| #define HAVE_TIME_H 1 +| #define HAVE_UNISTD_H 1 +| #define HAVE_UTIME_H 1 +| #define HAVE_WCHAR_H 1 +| #define HAVE_GETOPT_H 1 +| #define HAVE_FEATURES_H 1 +| #define HAVE_ENDIAN_H 1 +| #define HAVE_BYTESWAP_H 1 +| #define HAVE_SYS_PARAM_H 1 +| #define HAVE_SYS_IOCTL_H 1 +| #define HAVE_SYS_MOUNT_H 1 +| #define HAVE_SYS_STAT_H 1 +| #define HAVE_SYS_TYPES_H 1 +| #define HAVE_SYS_VFS_H 1 +| #define HAVE_SYS_STATVFS_H 1 +| #define HAVE_SYS_SYSMACROS_H 1 +| #define HAVE_LINUX_MAJOR_H 1 +| #define HAVE_LINUX_FD_H 1 +| #define HAVE_LINUX_HDREG_H 1 +| #define HAVE_SYSLOG_H 1 +| #define HAVE__BOOL 1 +| #define HAVE_STDBOOL_H 1 +| #define WORDS_LITTLEENDIAN 1 +| #define HAVE_STRUCT_STAT_ST_BLOCKS 1 +| #define HAVE_ST_BLOCKS 1 +| #define HAVE_STRUCT_STAT_ST_RDEV 1 +| /* end confdefs.h. */ +| #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 +| int +| main () +| { +| static struct stat ac_aggr; +| if (sizeof ac_aggr.st_atim) +| return 0; +| ; +| return 0; +| } +configure:21778: result: no +configure:21789: checking for struct stat.st_atimespec +configure:21817: arc-linux-uclibc-gcc -c -mA7 -g conftest.c >&5 +conftest.c: In function 'main': +conftest.c:102: error: 'struct stat' has no member named 'st_atimespec' +configure:21823: $? = 1 +configure: failed program was: +| /* confdefs.h. */ +| #define PACKAGE_NAME "ntfs-3g" +| #define PACKAGE_TARNAME "ntfs-3g" +| #define PACKAGE_VERSION "2010.5.16" +| #define PACKAGE_STRING "ntfs-3g 2010.5.16" +| #define PACKAGE_BUGREPORT "ntfs-3g-devel@lists.sf.net" +| #define PACKAGE "ntfs-3g" +| #define VERSION "2010.5.16" +| #define _GNU_SOURCE 1 +| #define STDC_HEADERS 1 +| #define HAVE_SYS_TYPES_H 1 +| #define HAVE_SYS_STAT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_MEMORY_H 1 +| #define HAVE_STRINGS_H 1 +| #define HAVE_INTTYPES_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_UNISTD_H 1 +| #define HAVE_DLFCN_H 1 +| #define _REENTRANT 1 +| #define FUSE_INTERNAL 1 +| #define STDC_HEADERS 1 +| #define HAVE_CTYPE_H 1 +| #define HAVE_FCNTL_H 1 +| #define HAVE_LIBGEN_H 1 +| #define HAVE_LIMITS_H 1 +| #define HAVE_LOCALE_H 1 +| #define HAVE_MNTENT_H 1 +| #define HAVE_STDDEF_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STDIO_H 1 +| #define HAVE_STDARG_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_STRINGS_H 1 +| #define HAVE_ERRNO_H 1 +| #define HAVE_TIME_H 1 +| #define HAVE_UNISTD_H 1 +| #define HAVE_UTIME_H 1 +| #define HAVE_WCHAR_H 1 +| #define HAVE_GETOPT_H 1 +| #define HAVE_FEATURES_H 1 +| #define HAVE_ENDIAN_H 1 +| #define HAVE_BYTESWAP_H 1 +| #define HAVE_SYS_PARAM_H 1 +| #define HAVE_SYS_IOCTL_H 1 +| #define HAVE_SYS_MOUNT_H 1 +| #define HAVE_SYS_STAT_H 1 +| #define HAVE_SYS_TYPES_H 1 +| #define HAVE_SYS_VFS_H 1 +| #define HAVE_SYS_STATVFS_H 1 +| #define HAVE_SYS_SYSMACROS_H 1 +| #define HAVE_LINUX_MAJOR_H 1 +| #define HAVE_LINUX_FD_H 1 +| #define HAVE_LINUX_HDREG_H 1 +| #define HAVE_SYSLOG_H 1 +| #define HAVE__BOOL 1 +| #define HAVE_STDBOOL_H 1 +| #define WORDS_LITTLEENDIAN 1 +| #define HAVE_STRUCT_STAT_ST_BLOCKS 1 +| #define HAVE_ST_BLOCKS 1 +| #define HAVE_STRUCT_STAT_ST_RDEV 1 +| /* end confdefs.h. */ +| #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 +| int +| main () +| { +| static struct stat ac_aggr; +| if (ac_aggr.st_atimespec) +| return 0; +| ; +| return 0; +| } +configure:21856: arc-linux-uclibc-gcc -c -mA7 -g conftest.c >&5 +conftest.c: In function 'main': +conftest.c:102: error: 'struct stat' has no member named 'st_atimespec' +configure:21862: $? = 1 +configure: failed program was: +| /* confdefs.h. */ +| #define PACKAGE_NAME "ntfs-3g" +| #define PACKAGE_TARNAME "ntfs-3g" +| #define PACKAGE_VERSION "2010.5.16" +| #define PACKAGE_STRING "ntfs-3g 2010.5.16" +| #define PACKAGE_BUGREPORT "ntfs-3g-devel@lists.sf.net" +| #define PACKAGE "ntfs-3g" +| #define VERSION "2010.5.16" +| #define _GNU_SOURCE 1 +| #define STDC_HEADERS 1 +| #define HAVE_SYS_TYPES_H 1 +| #define HAVE_SYS_STAT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_MEMORY_H 1 +| #define HAVE_STRINGS_H 1 +| #define HAVE_INTTYPES_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_UNISTD_H 1 +| #define HAVE_DLFCN_H 1 +| #define _REENTRANT 1 +| #define FUSE_INTERNAL 1 +| #define STDC_HEADERS 1 +| #define HAVE_CTYPE_H 1 +| #define HAVE_FCNTL_H 1 +| #define HAVE_LIBGEN_H 1 +| #define HAVE_LIMITS_H 1 +| #define HAVE_LOCALE_H 1 +| #define HAVE_MNTENT_H 1 +| #define HAVE_STDDEF_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STDIO_H 1 +| #define HAVE_STDARG_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_STRINGS_H 1 +| #define HAVE_ERRNO_H 1 +| #define HAVE_TIME_H 1 +| #define HAVE_UNISTD_H 1 +| #define HAVE_UTIME_H 1 +| #define HAVE_WCHAR_H 1 +| #define HAVE_GETOPT_H 1 +| #define HAVE_FEATURES_H 1 +| #define HAVE_ENDIAN_H 1 +| #define HAVE_BYTESWAP_H 1 +| #define HAVE_SYS_PARAM_H 1 +| #define HAVE_SYS_IOCTL_H 1 +| #define HAVE_SYS_MOUNT_H 1 +| #define HAVE_SYS_STAT_H 1 +| #define HAVE_SYS_TYPES_H 1 +| #define HAVE_SYS_VFS_H 1 +| #define HAVE_SYS_STATVFS_H 1 +| #define HAVE_SYS_SYSMACROS_H 1 +| #define HAVE_LINUX_MAJOR_H 1 +| #define HAVE_LINUX_FD_H 1 +| #define HAVE_LINUX_HDREG_H 1 +| #define HAVE_SYSLOG_H 1 +| #define HAVE__BOOL 1 +| #define HAVE_STDBOOL_H 1 +| #define WORDS_LITTLEENDIAN 1 +| #define HAVE_STRUCT_STAT_ST_BLOCKS 1 +| #define HAVE_ST_BLOCKS 1 +| #define HAVE_STRUCT_STAT_ST_RDEV 1 +| /* end confdefs.h. */ +| #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 +| int +| main () +| { +| static struct stat ac_aggr; +| if (sizeof ac_aggr.st_atimespec) +| return 0; +| ; +| return 0; +| } +configure:21880: result: no +configure:21891: checking for struct stat.st_atimensec +configure:21919: arc-linux-uclibc-gcc -c -mA7 -g conftest.c >&5 +configure:21925: $? = 0 +configure:21982: result: yes +configure:22152: checking for library containing getmntent +configure:22193: arc-linux-uclibc-gcc -o conftest -mA7 -g conftest.c >&5 +configure:22199: $? = 0 +configure:22227: result: none required +configure:22244: checking whether mbrtowc and mbstate_t are properly declared +configure:22274: arc-linux-uclibc-gcc -o conftest -mA7 -g conftest.c >&5 +configure:22280: $? = 0 +configure:22297: result: yes +configure:22307: checking for working memcmp +configure:22388: result: no +configure:22397: checking whether lstat dereferences a symlink specified with a trailing slash +configure:22468: result: no +configure:22487: checking whether stat accepts an empty string +configure:22545: result: yes +configure:22565: checking for strftime +configure:22621: arc-linux-uclibc-gcc -o conftest -mA7 -g conftest.c >&5 +conftest.c:92: warning: conflicting types for built-in function 'strftime' +configure:22627: $? = 0 +configure:22645: result: yes +configure:22734: checking for utime.h +configure:22740: result: yes +configure:22882: checking whether utime accepts a null argument +configure:22949: result: no +configure:22964: checking for vprintf +configure:23020: arc-linux-uclibc-gcc -o conftest -mA7 -g conftest.c >&5 +conftest.c:94: warning: conflicting types for built-in function 'vprintf' +configure:23026: $? = 0 +configure:23044: result: yes +configure:23051: checking for _doprnt +configure:23107: arc-linux-uclibc-gcc -o conftest -mA7 -g conftest.c >&5 +/tmp/ccW5tSya.o: In function `main': +/mnt/fileroot/michael.wang/linux-top-pub/ui_ref/trunk/build/packages/ntfs-3g-2010.5.16/conftest.c:106: undefined reference to `_doprnt' +collect2: ld returned 1 exit status +configure:23113: $? = 1 +configure: failed program was: +| /* confdefs.h. */ +| #define PACKAGE_NAME "ntfs-3g" +| #define PACKAGE_TARNAME "ntfs-3g" +| #define PACKAGE_VERSION "2010.5.16" +| #define PACKAGE_STRING "ntfs-3g 2010.5.16" +| #define PACKAGE_BUGREPORT "ntfs-3g-devel@lists.sf.net" +| #define PACKAGE "ntfs-3g" +| #define VERSION "2010.5.16" +| #define _GNU_SOURCE 1 +| #define STDC_HEADERS 1 +| #define HAVE_SYS_TYPES_H 1 +| #define HAVE_SYS_STAT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_MEMORY_H 1 +| #define HAVE_STRINGS_H 1 +| #define HAVE_INTTYPES_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_UNISTD_H 1 +| #define HAVE_DLFCN_H 1 +| #define _REENTRANT 1 +| #define FUSE_INTERNAL 1 +| #define STDC_HEADERS 1 +| #define HAVE_CTYPE_H 1 +| #define HAVE_FCNTL_H 1 +| #define HAVE_LIBGEN_H 1 +| #define HAVE_LIMITS_H 1 +| #define HAVE_LOCALE_H 1 +| #define HAVE_MNTENT_H 1 +| #define HAVE_STDDEF_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STDIO_H 1 +| #define HAVE_STDARG_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_STRINGS_H 1 +| #define HAVE_ERRNO_H 1 +| #define HAVE_TIME_H 1 +| #define HAVE_UNISTD_H 1 +| #define HAVE_UTIME_H 1 +| #define HAVE_WCHAR_H 1 +| #define HAVE_GETOPT_H 1 +| #define HAVE_FEATURES_H 1 +| #define HAVE_ENDIAN_H 1 +| #define HAVE_BYTESWAP_H 1 +| #define HAVE_SYS_PARAM_H 1 +| #define HAVE_SYS_IOCTL_H 1 +| #define HAVE_SYS_MOUNT_H 1 +| #define HAVE_SYS_STAT_H 1 +| #define HAVE_SYS_TYPES_H 1 +| #define HAVE_SYS_VFS_H 1 +| #define HAVE_SYS_STATVFS_H 1 +| #define HAVE_SYS_SYSMACROS_H 1 +| #define HAVE_LINUX_MAJOR_H 1 +| #define HAVE_LINUX_FD_H 1 +| #define HAVE_LINUX_HDREG_H 1 +| #define HAVE_SYSLOG_H 1 +| #define HAVE__BOOL 1 +| #define HAVE_STDBOOL_H 1 +| #define WORDS_LITTLEENDIAN 1 +| #define HAVE_STRUCT_STAT_ST_BLOCKS 1 +| #define HAVE_ST_BLOCKS 1 +| #define HAVE_STRUCT_STAT_ST_RDEV 1 +| #define HAVE_STRUCT_STAT_ST_ATIMENSEC 1 +| #define HAVE_GETMNTENT +| #define HAVE_MBRTOWC 1 +| #define HAVE_STAT_EMPTY_STRING_BUG 1 +| #define HAVE_STRFTIME 1 +| #define HAVE_UTIME_H 1 +| #define HAVE_VPRINTF 1 +| /* end confdefs.h. */ +| /* Define _doprnt to an innocuous variant, in case declares _doprnt. +| For example, HP-UX 11i declares gettimeofday. */ +| #define _doprnt innocuous__doprnt +| +| /* System header to define __stub macros and hopefully few prototypes, +| which can conflict with char _doprnt (); below. +| Prefer to if __STDC__ is defined, since +| exists even on freestanding compilers. */ +| +| #ifdef __STDC__ +| # include +| #else +| # include +| #endif +| +| #undef _doprnt +| +| /* 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 _doprnt (); +| /* 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__doprnt || defined __stub____doprnt +| choke me +| #endif +| +| int +| main () +| { +| return _doprnt (); +| ; +| return 0; +| } +configure:23130: result: no +configure:23181: checking for atexit +configure:23237: arc-linux-uclibc-gcc -o conftest -mA7 -g conftest.c >&5 +configure:23243: $? = 0 +configure:23261: result: yes +configure:23181: checking for basename +configure:23237: arc-linux-uclibc-gcc -o conftest -mA7 -g conftest.c >&5 +configure:23243: $? = 0 +configure:23261: result: yes +configure:23181: checking for daemon +configure:23237: arc-linux-uclibc-gcc -o conftest -mA7 -g conftest.c >&5 +configure:23243: $? = 0 +configure:23261: result: yes +configure:23181: checking for dup2 +configure:23237: arc-linux-uclibc-gcc -o conftest -mA7 -g conftest.c >&5 +configure:23243: $? = 0 +configure:23261: result: yes +configure:23181: checking for fdatasync +configure:23237: arc-linux-uclibc-gcc -o conftest -mA7 -g conftest.c >&5 +configure:23243: $? = 0 +configure:23261: result: yes +configure:23181: checking for ffs +configure:23237: arc-linux-uclibc-gcc -o conftest -mA7 -g conftest.c >&5 +conftest.c:100: warning: conflicting types for built-in function 'ffs' +configure:23243: $? = 0 +configure:23261: result: yes +configure:23181: checking for getopt_long +configure:23237: arc-linux-uclibc-gcc -o conftest -mA7 -g conftest.c >&5 +configure:23243: $? = 0 +configure:23261: result: yes +configure:23181: checking for hasmntopt +configure:23237: arc-linux-uclibc-gcc -o conftest -mA7 -g conftest.c >&5 +configure:23243: $? = 0 +configure:23261: result: yes +configure:23181: checking for mbsinit +configure:23237: arc-linux-uclibc-gcc -o conftest -mA7 -g conftest.c >&5 +configure:23243: $? = 0 +configure:23261: result: yes +configure:23181: checking for memmove +configure:23237: arc-linux-uclibc-gcc -o conftest -mA7 -g conftest.c >&5 +conftest.c:104: warning: conflicting types for built-in function 'memmove' +configure:23243: $? = 0 +configure:23261: result: yes +configure:23181: checking for memset +configure:23237: arc-linux-uclibc-gcc -o conftest -mA7 -g conftest.c >&5 +conftest.c:105: warning: conflicting types for built-in function 'memset' +configure:23243: $? = 0 +configure:23261: result: yes +configure:23181: checking for realpath +configure:23237: arc-linux-uclibc-gcc -o conftest -mA7 -g conftest.c >&5 +configure:23243: $? = 0 +configure:23261: result: yes +configure:23181: checking for regcomp +configure:23237: arc-linux-uclibc-gcc -o conftest -mA7 -g conftest.c >&5 +configure:23243: $? = 0 +configure:23261: result: yes +configure:23181: checking for setlocale +configure:23237: arc-linux-uclibc-gcc -o conftest -mA7 -g conftest.c >&5 +configure:23243: $? = 0 +configure:23261: result: yes +configure:23181: checking for setxattr +configure:23237: arc-linux-uclibc-gcc -o conftest -mA7 -g conftest.c >&5 +configure:23243: $? = 0 +configure:23261: result: yes +configure:23181: checking for strcasecmp +configure:23237: arc-linux-uclibc-gcc -o conftest -mA7 -g conftest.c >&5 +conftest.c:110: warning: conflicting types for built-in function 'strcasecmp' +configure:23243: $? = 0 +configure:23261: result: yes +configure:23181: checking for strchr +configure:23237: arc-linux-uclibc-gcc -o conftest -mA7 -g conftest.c >&5 +conftest.c:111: warning: conflicting types for built-in function 'strchr' +configure:23243: $? = 0 +configure:23261: result: yes +configure:23181: checking for strdup +configure:23237: arc-linux-uclibc-gcc -o conftest -mA7 -g conftest.c >&5 +conftest.c:112: warning: conflicting types for built-in function 'strdup' +configure:23243: $? = 0 +configure:23261: result: yes +configure:23181: checking for strerror +configure:23237: arc-linux-uclibc-gcc -o conftest -mA7 -g conftest.c >&5 +configure:23243: $? = 0 +configure:23261: result: yes +configure:23181: checking for strnlen +configure:23237: arc-linux-uclibc-gcc -o conftest -mA7 -g conftest.c >&5 +configure:23243: $? = 0 +configure:23261: result: yes +configure:23181: checking for strsep +configure:23237: arc-linux-uclibc-gcc -o conftest -mA7 -g conftest.c >&5 +configure:23243: $? = 0 +configure:23261: result: yes +configure:23181: checking for strtol +configure:23237: arc-linux-uclibc-gcc -o conftest -mA7 -g conftest.c >&5 +configure:23243: $? = 0 +configure:23261: result: yes +configure:23181: checking for strtoul +configure:23237: arc-linux-uclibc-gcc -o conftest -mA7 -g conftest.c >&5 +configure:23243: $? = 0 +configure:23261: result: yes +configure:23181: checking for sysconf +configure:23237: arc-linux-uclibc-gcc -o conftest -mA7 -g conftest.c >&5 +configure:23243: $? = 0 +configure:23261: result: yes +configure:23181: checking for utime +configure:23237: arc-linux-uclibc-gcc -o conftest -mA7 -g conftest.c >&5 +configure:23243: $? = 0 +configure:23261: result: yes +configure:23181: checking for utimensat +configure:23237: arc-linux-uclibc-gcc -o conftest -mA7 -g conftest.c >&5 +/tmp/ccaBiGqI.o: In function `main': +/mnt/fileroot/michael.wang/linux-top-pub/ui_ref/trunk/build/packages/ntfs-3g-2010.5.16/conftest.c:131: undefined reference to `utimensat' +collect2: ld returned 1 exit status +configure:23243: $? = 1 +configure: failed program was: +| /* confdefs.h. */ +| #define PACKAGE_NAME "ntfs-3g" +| #define PACKAGE_TARNAME "ntfs-3g" +| #define PACKAGE_VERSION "2010.5.16" +| #define PACKAGE_STRING "ntfs-3g 2010.5.16" +| #define PACKAGE_BUGREPORT "ntfs-3g-devel@lists.sf.net" +| #define PACKAGE "ntfs-3g" +| #define VERSION "2010.5.16" +| #define _GNU_SOURCE 1 +| #define STDC_HEADERS 1 +| #define HAVE_SYS_TYPES_H 1 +| #define HAVE_SYS_STAT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_MEMORY_H 1 +| #define HAVE_STRINGS_H 1 +| #define HAVE_INTTYPES_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_UNISTD_H 1 +| #define HAVE_DLFCN_H 1 +| #define _REENTRANT 1 +| #define FUSE_INTERNAL 1 +| #define STDC_HEADERS 1 +| #define HAVE_CTYPE_H 1 +| #define HAVE_FCNTL_H 1 +| #define HAVE_LIBGEN_H 1 +| #define HAVE_LIMITS_H 1 +| #define HAVE_LOCALE_H 1 +| #define HAVE_MNTENT_H 1 +| #define HAVE_STDDEF_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STDIO_H 1 +| #define HAVE_STDARG_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_STRINGS_H 1 +| #define HAVE_ERRNO_H 1 +| #define HAVE_TIME_H 1 +| #define HAVE_UNISTD_H 1 +| #define HAVE_UTIME_H 1 +| #define HAVE_WCHAR_H 1 +| #define HAVE_GETOPT_H 1 +| #define HAVE_FEATURES_H 1 +| #define HAVE_ENDIAN_H 1 +| #define HAVE_BYTESWAP_H 1 +| #define HAVE_SYS_PARAM_H 1 +| #define HAVE_SYS_IOCTL_H 1 +| #define HAVE_SYS_MOUNT_H 1 +| #define HAVE_SYS_STAT_H 1 +| #define HAVE_SYS_TYPES_H 1 +| #define HAVE_SYS_VFS_H 1 +| #define HAVE_SYS_STATVFS_H 1 +| #define HAVE_SYS_SYSMACROS_H 1 +| #define HAVE_LINUX_MAJOR_H 1 +| #define HAVE_LINUX_FD_H 1 +| #define HAVE_LINUX_HDREG_H 1 +| #define HAVE_SYSLOG_H 1 +| #define HAVE__BOOL 1 +| #define HAVE_STDBOOL_H 1 +| #define WORDS_LITTLEENDIAN 1 +| #define HAVE_STRUCT_STAT_ST_BLOCKS 1 +| #define HAVE_ST_BLOCKS 1 +| #define HAVE_STRUCT_STAT_ST_RDEV 1 +| #define HAVE_STRUCT_STAT_ST_ATIMENSEC 1 +| #define HAVE_GETMNTENT +| #define HAVE_MBRTOWC 1 +| #define HAVE_STAT_EMPTY_STRING_BUG 1 +| #define HAVE_STRFTIME 1 +| #define HAVE_UTIME_H 1 +| #define HAVE_VPRINTF 1 +| #define HAVE_ATEXIT 1 +| #define HAVE_BASENAME 1 +| #define HAVE_DAEMON 1 +| #define HAVE_DUP2 1 +| #define HAVE_FDATASYNC 1 +| #define HAVE_FFS 1 +| #define HAVE_GETOPT_LONG 1 +| #define HAVE_HASMNTOPT 1 +| #define HAVE_MBSINIT 1 +| #define HAVE_MEMMOVE 1 +| #define HAVE_MEMSET 1 +| #define HAVE_REALPATH 1 +| #define HAVE_REGCOMP 1 +| #define HAVE_SETLOCALE 1 +| #define HAVE_SETXATTR 1 +| #define HAVE_STRCASECMP 1 +| #define HAVE_STRCHR 1 +| #define HAVE_STRDUP 1 +| #define HAVE_STRERROR 1 +| #define HAVE_STRNLEN 1 +| #define HAVE_STRSEP 1 +| #define HAVE_STRTOL 1 +| #define HAVE_STRTOUL 1 +| #define HAVE_SYSCONF 1 +| #define HAVE_UTIME 1 +| /* end confdefs.h. */ +| /* Define utimensat to an innocuous variant, in case declares utimensat. +| For example, HP-UX 11i declares gettimeofday. */ +| #define utimensat innocuous_utimensat +| +| /* System header to define __stub macros and hopefully few prototypes, +| which can conflict with char utimensat (); below. +| Prefer to if __STDC__ is defined, since +| exists even on freestanding compilers. */ +| +| #ifdef __STDC__ +| # include +| #else +| # include +| #endif +| +| #undef utimensat +| +| /* 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 utimensat (); +| /* 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_utimensat || defined __stub___utimensat +| choke me +| #endif +| +| int +| main () +| { +| return utimensat (); +| ; +| return 0; +| } +configure:23261: result: no +configure:23181: checking for gettimeofday +configure:23237: arc-linux-uclibc-gcc -o conftest -mA7 -g conftest.c >&5 +configure:23243: $? = 0 +configure:23261: result: yes +configure:23181: checking for clock_gettime +configure:23237: arc-linux-uclibc-gcc -o conftest -mA7 -g conftest.c >&5 +configure:23243: $? = 0 +configure:23261: result: yes +configure:23181: checking for fork +configure:23237: arc-linux-uclibc-gcc -o conftest -mA7 -g conftest.c >&5 +conftest.c:122: warning: conflicting types for built-in function 'fork' +configure:23243: $? = 0 +configure:23261: result: yes +configure:23278: checking for special C compiler options needed for large files +configure:23371: result: no +configure:23377: checking for _FILE_OFFSET_BITS value needed for large files +configure:23412: arc-linux-uclibc-gcc -c -mA7 -g conftest.c >&5 +conftest.c:106: warning: left shift count >= width of type +conftest.c:106: warning: left shift count >= width of type +conftest.c:108: error: size of array 'off_t_is_large' is negative +configure:23418: $? = 1 +configure: failed program was: +| /* confdefs.h. */ +| #define PACKAGE_NAME "ntfs-3g" +| #define PACKAGE_TARNAME "ntfs-3g" +| #define PACKAGE_VERSION "2010.5.16" +| #define PACKAGE_STRING "ntfs-3g 2010.5.16" +| #define PACKAGE_BUGREPORT "ntfs-3g-devel@lists.sf.net" +| #define PACKAGE "ntfs-3g" +| #define VERSION "2010.5.16" +| #define _GNU_SOURCE 1 +| #define STDC_HEADERS 1 +| #define HAVE_SYS_TYPES_H 1 +| #define HAVE_SYS_STAT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_MEMORY_H 1 +| #define HAVE_STRINGS_H 1 +| #define HAVE_INTTYPES_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_UNISTD_H 1 +| #define HAVE_DLFCN_H 1 +| #define _REENTRANT 1 +| #define FUSE_INTERNAL 1 +| #define STDC_HEADERS 1 +| #define HAVE_CTYPE_H 1 +| #define HAVE_FCNTL_H 1 +| #define HAVE_LIBGEN_H 1 +| #define HAVE_LIMITS_H 1 +| #define HAVE_LOCALE_H 1 +| #define HAVE_MNTENT_H 1 +| #define HAVE_STDDEF_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STDIO_H 1 +| #define HAVE_STDARG_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_STRINGS_H 1 +| #define HAVE_ERRNO_H 1 +| #define HAVE_TIME_H 1 +| #define HAVE_UNISTD_H 1 +| #define HAVE_UTIME_H 1 +| #define HAVE_WCHAR_H 1 +| #define HAVE_GETOPT_H 1 +| #define HAVE_FEATURES_H 1 +| #define HAVE_ENDIAN_H 1 +| #define HAVE_BYTESWAP_H 1 +| #define HAVE_SYS_PARAM_H 1 +| #define HAVE_SYS_IOCTL_H 1 +| #define HAVE_SYS_MOUNT_H 1 +| #define HAVE_SYS_STAT_H 1 +| #define HAVE_SYS_TYPES_H 1 +| #define HAVE_SYS_VFS_H 1 +| #define HAVE_SYS_STATVFS_H 1 +| #define HAVE_SYS_SYSMACROS_H 1 +| #define HAVE_LINUX_MAJOR_H 1 +| #define HAVE_LINUX_FD_H 1 +| #define HAVE_LINUX_HDREG_H 1 +| #define HAVE_SYSLOG_H 1 +| #define HAVE__BOOL 1 +| #define HAVE_STDBOOL_H 1 +| #define WORDS_LITTLEENDIAN 1 +| #define HAVE_STRUCT_STAT_ST_BLOCKS 1 +| #define HAVE_ST_BLOCKS 1 +| #define HAVE_STRUCT_STAT_ST_RDEV 1 +| #define HAVE_STRUCT_STAT_ST_ATIMENSEC 1 +| #define HAVE_GETMNTENT +| #define HAVE_MBRTOWC 1 +| #define HAVE_STAT_EMPTY_STRING_BUG 1 +| #define HAVE_STRFTIME 1 +| #define HAVE_UTIME_H 1 +| #define HAVE_VPRINTF 1 +| #define HAVE_ATEXIT 1 +| #define HAVE_BASENAME 1 +| #define HAVE_DAEMON 1 +| #define HAVE_DUP2 1 +| #define HAVE_FDATASYNC 1 +| #define HAVE_FFS 1 +| #define HAVE_GETOPT_LONG 1 +| #define HAVE_HASMNTOPT 1 +| #define HAVE_MBSINIT 1 +| #define HAVE_MEMMOVE 1 +| #define HAVE_MEMSET 1 +| #define HAVE_REALPATH 1 +| #define HAVE_REGCOMP 1 +| #define HAVE_SETLOCALE 1 +| #define HAVE_SETXATTR 1 +| #define HAVE_STRCASECMP 1 +| #define HAVE_STRCHR 1 +| #define HAVE_STRDUP 1 +| #define HAVE_STRERROR 1 +| #define HAVE_STRNLEN 1 +| #define HAVE_STRSEP 1 +| #define HAVE_STRTOL 1 +| #define HAVE_STRTOUL 1 +| #define HAVE_SYSCONF 1 +| #define HAVE_UTIME 1 +| #define HAVE_GETTIMEOFDAY 1 +| #define HAVE_CLOCK_GETTIME 1 +| #define HAVE_FORK 1 +| /* end confdefs.h. */ +| #include +| /* Check that off_t can represent 2**63 - 1 correctly. +| We can't simply define LARGE_OFF_T to be 9223372036854775807, +| since some C++ compilers masquerading as C compilers +| incorrectly reject 9223372036854775807. */ +| #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) +| int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 +| && LARGE_OFF_T % 2147483647 == 1) +| ? 1 : -1]; +| int +| main () +| { +| +| ; +| return 0; +| } +configure:23462: arc-linux-uclibc-gcc -c -mA7 -g conftest.c >&5 +configure:23468: $? = 0 +configure:23486: result: 64 +configure:23957: creating ./config.status + +## ---------------------- ## +## Running config.status. ## +## ---------------------- ## + +This file was extended by ntfs-3g config.status 2010.5.16, which was +generated by GNU Autoconf 2.61. Invocation command line was + + CONFIG_FILES = + CONFIG_HEADERS = + CONFIG_LINKS = + CONFIG_COMMANDS = + $ ./config.status + +on announce + +config.status:714: creating Makefile +config.status:714: creating include/Makefile +config.status:714: creating include/fuse-lite/Makefile +config.status:714: creating include/ntfs-3g/Makefile +config.status:714: creating libfuse-lite/Makefile +config.status:714: creating libntfs-3g/Makefile +config.status:714: creating libntfs-3g/libntfs-3g.pc +config.status:714: creating libntfs-3g/libntfs-3g.script.so +config.status:714: creating src/Makefile +config.status:714: creating src/ntfs-3g.8 +config.status:714: creating src/ntfs-3g.probe.8 +config.status:714: creating src/ntfs-3g.usermap.8 +config.status:714: creating src/ntfs-3g.secaudit.8 +config.status:714: creating config.h +config.status:1084: executing depfiles commands + +## ---------------- ## +## Cache variables. ## +## ---------------- ## + +ac_cv_build=i686-pc-linux-gnu +ac_cv_c_bigendian=no +ac_cv_c_compiler_gnu=yes +ac_cv_c_inline=inline +ac_cv_cxx_compiler_gnu=yes +ac_cv_env_CCC_set= +ac_cv_env_CCC_value= +ac_cv_env_CC_set=set +ac_cv_env_CC_value=arc-linux-uclibc-gcc +ac_cv_env_CFLAGS_set=set +ac_cv_env_CFLAGS_value='-mA7 -g' +ac_cv_env_CPPFLAGS_set= +ac_cv_env_CPPFLAGS_value= +ac_cv_env_CPP_set= +ac_cv_env_CPP_value= +ac_cv_env_CXXCPP_set= +ac_cv_env_CXXCPP_value= +ac_cv_env_CXXFLAGS_set= +ac_cv_env_CXXFLAGS_value= +ac_cv_env_CXX_set= +ac_cv_env_CXX_value= +ac_cv_env_F77_set= +ac_cv_env_F77_value= +ac_cv_env_FFLAGS_set= +ac_cv_env_FFLAGS_value= +ac_cv_env_FUSE_MODULE_CFLAGS_set= +ac_cv_env_FUSE_MODULE_CFLAGS_value= +ac_cv_env_FUSE_MODULE_LIBS_set= +ac_cv_env_FUSE_MODULE_LIBS_value= +ac_cv_env_LDCONFIG_set= +ac_cv_env_LDCONFIG_value= +ac_cv_env_LDFLAGS_set= +ac_cv_env_LDFLAGS_value= +ac_cv_env_LIBS_set= +ac_cv_env_LIBS_value= +ac_cv_env_PKG_CONFIG_set= +ac_cv_env_PKG_CONFIG_value= +ac_cv_env_build_alias_set= +ac_cv_env_build_alias_value= +ac_cv_env_host_alias_set=set +ac_cv_env_host_alias_value=arc-linux-uclibc +ac_cv_env_target_alias_set= +ac_cv_env_target_alias_value= +ac_cv_f77_compiler_gnu=no +ac_cv_func__doprnt=no +ac_cv_func_atexit=yes +ac_cv_func_basename=yes +ac_cv_func_clock_gettime=yes +ac_cv_func_daemon=yes +ac_cv_func_dup2=yes +ac_cv_func_fdatasync=yes +ac_cv_func_ffs=yes +ac_cv_func_fork=yes +ac_cv_func_getmntent=yes +ac_cv_func_getopt_long=yes +ac_cv_func_gettimeofday=yes +ac_cv_func_hasmntopt=yes +ac_cv_func_lstat_dereferences_slashed_symlink=no +ac_cv_func_mbrtowc=yes +ac_cv_func_mbsinit=yes +ac_cv_func_memcmp_working=no +ac_cv_func_memmove=yes +ac_cv_func_memset=yes +ac_cv_func_realpath=yes +ac_cv_func_regcomp=yes +ac_cv_func_setlocale=yes +ac_cv_func_setxattr=yes +ac_cv_func_stat_empty_string_bug=yes +ac_cv_func_strcasecmp=yes +ac_cv_func_strchr=yes +ac_cv_func_strdup=yes +ac_cv_func_strerror=yes +ac_cv_func_strftime=yes +ac_cv_func_strnlen=yes +ac_cv_func_strsep=yes +ac_cv_func_strtol=yes +ac_cv_func_strtoul=yes +ac_cv_func_sysconf=yes +ac_cv_func_utime=yes +ac_cv_func_utime_null=no +ac_cv_func_utimensat=no +ac_cv_func_vprintf=yes +ac_cv_header_byteswap_h=yes +ac_cv_header_ctype_h=yes +ac_cv_header_dlfcn_h=yes +ac_cv_header_endian_h=yes +ac_cv_header_errno_h=yes +ac_cv_header_fcntl_h=yes +ac_cv_header_features_h=yes +ac_cv_header_getopt_h=yes +ac_cv_header_inttypes_h=yes +ac_cv_header_libgen_h=yes +ac_cv_header_libintl_h=no +ac_cv_header_limits_h=yes +ac_cv_header_linux_fd_h=yes +ac_cv_header_linux_hdreg_h=yes +ac_cv_header_linux_major_h=yes +ac_cv_header_locale_h=yes +ac_cv_header_machine_endian_h=no +ac_cv_header_memory_h=yes +ac_cv_header_mntent_h=yes +ac_cv_header_stdarg_h=yes +ac_cv_header_stdbool_h=yes +ac_cv_header_stdc=yes +ac_cv_header_stddef_h=yes +ac_cv_header_stdint_h=yes +ac_cv_header_stdio_h=yes +ac_cv_header_stdlib_h=yes +ac_cv_header_string_h=yes +ac_cv_header_strings_h=yes +ac_cv_header_sys_byteorder_h=no +ac_cv_header_sys_endian_h=no +ac_cv_header_sys_ioctl_h=yes +ac_cv_header_sys_mkdev_h=no +ac_cv_header_sys_mount_h=yes +ac_cv_header_sys_param_h=yes +ac_cv_header_sys_stat_h=yes +ac_cv_header_sys_statvfs_h=yes +ac_cv_header_sys_sysmacros_h=yes +ac_cv_header_sys_types_h=yes +ac_cv_header_sys_vfs_h=yes +ac_cv_header_syslog_h=yes +ac_cv_header_time_h=yes +ac_cv_header_unistd_h=yes +ac_cv_header_utime_h=yes +ac_cv_header_wchar_h=yes +ac_cv_header_windows_h=no +ac_cv_host=arc-unknown-linux-uclibc +ac_cv_lib_pthread_pthread_create=yes +ac_cv_member_struct_stat_st_atim=no +ac_cv_member_struct_stat_st_atimensec=yes +ac_cv_member_struct_stat_st_atimespec=no +ac_cv_member_struct_stat_st_blocks=yes +ac_cv_member_struct_stat_st_rdev=yes +ac_cv_objext=o +ac_cv_path_EGREP='/bin/grep -E' +ac_cv_path_GREP=/bin/grep +ac_cv_path_LDCONFIG=/sbin/ldconfig +ac_cv_path_MV=/bin/mv +ac_cv_path_RM=/bin/rm +ac_cv_path_SED=/bin/sed +ac_cv_path_install='/usr/bin/install -c' +ac_cv_path_mkdir=/bin/mkdir +ac_cv_prog_AR=arc-linux-uclibc-ar +ac_cv_prog_AWK=mawk +ac_cv_prog_CC=arc-linux-uclibc-gcc +ac_cv_prog_CPP='arc-linux-uclibc-gcc -E' +ac_cv_prog_CXX=arc-linux-uclibc-g++ +ac_cv_prog_CXXCPP='arc-linux-uclibc-g++ -E' +ac_cv_prog_RANLIB=arc-linux-uclibc-ranlib +ac_cv_prog_STRIP=arc-linux-uclibc-strip +ac_cv_prog_cc_arc_linux_uclibc_gcc_c_o=yes +ac_cv_prog_cc_c89= +ac_cv_prog_cc_g=yes +ac_cv_prog_cxx_g=yes +ac_cv_prog_f77_g=no +ac_cv_prog_make_make_set=yes +ac_cv_search_getmntent='none required' +ac_cv_sys_file_offset_bits=64 +ac_cv_sys_largefile_CC=no +ac_cv_target=arc-unknown-linux-uclibc +ac_cv_type__Bool=yes +ac_cv_type_off_t=yes +ac_cv_type_size_t=yes +am_cv_CC_dependencies_compiler_type=gcc3 +am_cv_CXX_dependencies_compiler_type=gcc3 +lt_cv_deplibs_check_method=pass_all +lt_cv_file_magic_cmd='$MAGIC_CMD' +lt_cv_file_magic_test_file= +lt_cv_ld_reload_flag=-r +lt_cv_objdir=.libs +lt_cv_path_LD=/opt/gnutools/arc2.3-p0/uclibc-4.2.1/arc-linux-uclibc/bin/ld +lt_cv_path_LDCXX=/opt/gnutools/arc2.3-p0/uclibc-4.2.1/arc-linux-uclibc/bin/ld +lt_cv_path_NM='/opt/gnutools/arc2.3-p0/uclibc-4.2.1/bin/arc-linux-uclibc-nm -B' +lt_cv_path_SED=/bin/sed +lt_cv_prog_compiler_c_o=yes +lt_cv_prog_compiler_c_o_CXX=yes +lt_cv_prog_compiler_pic_works=yes +lt_cv_prog_compiler_pic_works_CXX=yes +lt_cv_prog_compiler_rtti_exceptions=no +lt_cv_prog_compiler_static_works=yes +lt_cv_prog_compiler_static_works_CXX=yes +lt_cv_prog_gnu_ld=yes +lt_cv_prog_gnu_ldcxx=yes +lt_cv_sys_global_symbol_pipe='sed -n -e '\''s/^.*[ ]\([ABCDGIRSTW][ABCDGIRSTW]*\)[ ][ ]*\([_A-Za-z][_A-Za-z0-9]*\)$/\1 \2 \2/p'\''' +lt_cv_sys_global_symbol_to_c_name_address='sed -n -e '\''s/^: \([^ ]*\) $/ {\"\1\", (lt_ptr) 0},/p'\'' -e '\''s/^[BCDEGRST] \([^ ]*\) \([^ ]*\)$/ {"\2", (lt_ptr) \&\2},/p'\''' +lt_cv_sys_global_symbol_to_cdecl='sed -n -e '\''s/^. .* \(.*\)$/extern int \1;/p'\''' +lt_cv_sys_lib_dlsearch_path_spec='/lib /usr/lib /lib/i486-linux-gnu /usr/lib/i486-linux-gnu /usr/lib/alsa-lib /usr/local/lib ' +lt_cv_sys_lib_search_path_spec='/opt/gnutools/arc2.3-p0/uclibc-4.2.1/lib/gcc/arc-linux-uclibc/4.2.1 /opt/gnutools/arc2.3-p0/uclibc-4.2.1/arc-linux-uclibc/lib' +lt_cv_sys_max_cmd_len=805306365 +lt_lt_cv_prog_compiler_c_o='"yes"' +lt_lt_cv_prog_compiler_c_o_CXX='"yes"' +lt_lt_cv_sys_global_symbol_pipe='"sed -n -e '\''s/^.*[ ]\\([ABCDGIRSTW][ABCDGIRSTW]*\\)[ ][ ]*\\([_A-Za-z][_A-Za-z0-9]*\\)\$/\\1 \\2 \\2/p'\''"' +lt_lt_cv_sys_global_symbol_to_c_name_address='"sed -n -e '\''s/^: \\([^ ]*\\) \$/ {\\\"\\1\\\", (lt_ptr) 0},/p'\'' -e '\''s/^[BCDEGRST] \\([^ ]*\\) \\([^ ]*\\)\$/ {\"\\2\", (lt_ptr) \\&\\2},/p'\''"' +lt_lt_cv_sys_global_symbol_to_cdecl='"sed -n -e '\''s/^. .* \\(.*\\)\$/extern int \\1;/p'\''"' + +## ----------------- ## +## Output variables. ## +## ----------------- ## + +ACLOCAL='${SHELL} /mnt/fileroot/michael.wang/linux-top-pub/ui_ref/trunk/build/packages/ntfs-3g-2010.5.16/missing --run aclocal-1.10' +AMDEPBACKSLASH='\' +AMDEP_FALSE='#' +AMDEP_TRUE='' +AMTAR='${SHELL} /mnt/fileroot/michael.wang/linux-top-pub/ui_ref/trunk/build/packages/ntfs-3g-2010.5.16/missing --run tar' +AR='arc-linux-uclibc-ar' +AUTOCONF='${SHELL} /mnt/fileroot/michael.wang/linux-top-pub/ui_ref/trunk/build/packages/ntfs-3g-2010.5.16/missing --run autoconf' +AUTOHEADER='${SHELL} /mnt/fileroot/michael.wang/linux-top-pub/ui_ref/trunk/build/packages/ntfs-3g-2010.5.16/missing --run autoheader' +AUTOMAKE='${SHELL} /mnt/fileroot/michael.wang/linux-top-pub/ui_ref/trunk/build/packages/ntfs-3g-2010.5.16/missing --run automake-1.10' +AWK='mawk' +CC='arc-linux-uclibc-gcc' +CCDEPMODE='depmode=gcc3' +CFLAGS='-mA7 -g -Wall' +CPP='arc-linux-uclibc-gcc -E' +CPPFLAGS='' +CXX='arc-linux-uclibc-g++' +CXXCPP='arc-linux-uclibc-g++ -E' +CXXDEPMODE='depmode=gcc3' +CXXFLAGS='-g -O2' +CYGPATH_W='echo' +DEFS='-DHAVE_CONFIG_H' +DEPDIR='.deps' +DSYMUTIL='' +ECHO='echo' +ECHO_C='' +ECHO_N='-n' +ECHO_T='' +EGREP='/bin/grep -E' +ENABLE_MOUNT_HELPER_FALSE='' +ENABLE_MOUNT_HELPER_TRUE='#' +EXEEXT='' +F77='' +FFLAGS='' +FUSE_INTERNAL_FALSE='#' +FUSE_INTERNAL_TRUE='' +FUSE_MODULE_CFLAGS='' +FUSE_MODULE_LIBS='' +GENERATE_LDSCRIPT_FALSE='' +GENERATE_LDSCRIPT_TRUE='#' +GREP='/bin/grep' +INSTALL_DATA='${INSTALL} -m 644' +INSTALL_LIBRARY_FALSE='#' +INSTALL_LIBRARY_TRUE='' +INSTALL_PROGRAM='${INSTALL}' +INSTALL_SCRIPT='${INSTALL}' +INSTALL_STRIP_PROGRAM='$(install_sh) -c -s' +LDCONFIG='/sbin/ldconfig' +LDFLAGS='' +LIBFUSE_LITE_LIBS=' -lpthread' +LIBNTFS_3G_VERSION='76' +LIBOBJS=' ${LIBOBJDIR}memcmp$U.o ${LIBOBJDIR}lstat$U.o ${LIBOBJDIR}stat$U.o' +LIBS='' +LIBTOOL='$(SHELL) $(top_builddir)/libtool' +LN_S='ln -s' +LTLIBOBJS=' ${LIBOBJDIR}memcmp$U.lo ${LIBOBJDIR}lstat$U.lo ${LIBOBJDIR}stat$U.lo' +MAINT='#' +MAINTAINER_MODE_FALSE='' +MAINTAINER_MODE_TRUE='#' +MAKEINFO='${SHELL} /mnt/fileroot/michael.wang/linux-top-pub/ui_ref/trunk/build/packages/ntfs-3g-2010.5.16/missing --run makeinfo' +MKDIR_P='/bin/mkdir -p' +MV='/bin/mv' +NMEDIT='' +NTFS_DEVICE_DEFAULT_IO_OPS_FALSE='#' +NTFS_DEVICE_DEFAULT_IO_OPS_TRUE='' +OBJEXT='o' +OUTPUT_FORMAT='' +PACKAGE='ntfs-3g' +PACKAGE_BUGREPORT='ntfs-3g-devel@lists.sf.net' +PACKAGE_NAME='ntfs-3g' +PACKAGE_STRING='ntfs-3g 2010.5.16' +PACKAGE_TARNAME='ntfs-3g' +PACKAGE_VERSION='2010.5.16' +PATH_SEPARATOR=':' +PKG_CONFIG='' +RANLIB='arc-linux-uclibc-ranlib' +REALLYSTATIC_FALSE='' +REALLYSTATIC_TRUE='#' +RM='/bin/rm' +RUN_LDCONFIG_FALSE='' +RUN_LDCONFIG_TRUE='#' +SED='/bin/sed' +SET_MAKE='' +SHELL='/bin/bash' +STRIP='arc-linux-uclibc-strip' +VERSION='2010.5.16' +WINDOWS_FALSE='' +WINDOWS_TRUE='#' +ac_ct_CC='' +ac_ct_CXX='' +ac_ct_F77='' +am__fastdepCC_FALSE='#' +am__fastdepCC_TRUE='' +am__fastdepCXX_FALSE='#' +am__fastdepCXX_TRUE='' +am__include='include' +am__isrc='' +am__leading_dot='.' +am__quote='' +am__tar='${AMTAR} chof - "$$tardir"' +am__untar='${AMTAR} xf -' +bindir='${exec_prefix}/bin' +build='i686-pc-linux-gnu' +build_alias='' +build_cpu='i686' +build_os='linux-gnu' +build_vendor='pc' +datadir='${datarootdir}' +datarootdir='${prefix}/share' +docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' +dvidir='${docdir}' +exec_prefix='/mnt/fileroot/michael.wang/linux-top-pub/ui_ref/trunk/bld_7266_h_64x2/./rootfs' +host='arc-unknown-linux-uclibc' +host_alias='arc-linux-uclibc' +host_cpu='arc' +host_os='linux-uclibc' +host_vendor='unknown' +htmldir='${docdir}' +includedir='${prefix}/include' +infodir='${datarootdir}/info' +install_sh='$(SHELL) /mnt/fileroot/michael.wang/linux-top-pub/ui_ref/trunk/build/packages/ntfs-3g-2010.5.16/install-sh' +libdir='${exec_prefix}/lib' +libexecdir='${exec_prefix}/libexec' +localedir='${datarootdir}/locale' +localstatedir='${prefix}/var' +mandir='${datarootdir}/man' +mkdir_p='/bin/mkdir -p' +ntfs3gincludedir='$(includedir)/ntfs-3g' +oldincludedir='/usr/include' +pdfdir='${docdir}' +pkgconfigdir='$(libdir)/pkgconfig' +prefix='/mnt/fileroot/michael.wang/linux-top-pub/ui_ref/trunk/bld_7266_h_64x2/./rootfs' +program_transform_name='s,x,x,' +psdir='${docdir}' +rootbindir='$(bindir)' +rootlibdir='$(libdir)' +rootsbindir='$(sbindir)' +sbindir='${exec_prefix}/sbin' +sharedstatedir='${prefix}/com' +sysconfdir='${prefix}/etc' +target='arc-unknown-linux-uclibc' +target_alias='' +target_cpu='arc' +target_os='linux-uclibc' +target_vendor='unknown' + +## ----------- ## +## confdefs.h. ## +## ----------- ## + +#define PACKAGE_NAME "ntfs-3g" +#define PACKAGE_TARNAME "ntfs-3g" +#define PACKAGE_VERSION "2010.5.16" +#define PACKAGE_STRING "ntfs-3g 2010.5.16" +#define PACKAGE_BUGREPORT "ntfs-3g-devel@lists.sf.net" +#define PACKAGE "ntfs-3g" +#define VERSION "2010.5.16" +#define _GNU_SOURCE 1 +#define STDC_HEADERS 1 +#define HAVE_SYS_TYPES_H 1 +#define HAVE_SYS_STAT_H 1 +#define HAVE_STDLIB_H 1 +#define HAVE_STRING_H 1 +#define HAVE_MEMORY_H 1 +#define HAVE_STRINGS_H 1 +#define HAVE_INTTYPES_H 1 +#define HAVE_STDINT_H 1 +#define HAVE_UNISTD_H 1 +#define HAVE_DLFCN_H 1 +#define _REENTRANT 1 +#define FUSE_INTERNAL 1 +#define STDC_HEADERS 1 +#define HAVE_CTYPE_H 1 +#define HAVE_FCNTL_H 1 +#define HAVE_LIBGEN_H 1 +#define HAVE_LIMITS_H 1 +#define HAVE_LOCALE_H 1 +#define HAVE_MNTENT_H 1 +#define HAVE_STDDEF_H 1 +#define HAVE_STDINT_H 1 +#define HAVE_STDLIB_H 1 +#define HAVE_STDIO_H 1 +#define HAVE_STDARG_H 1 +#define HAVE_STRING_H 1 +#define HAVE_STRINGS_H 1 +#define HAVE_ERRNO_H 1 +#define HAVE_TIME_H 1 +#define HAVE_UNISTD_H 1 +#define HAVE_UTIME_H 1 +#define HAVE_WCHAR_H 1 +#define HAVE_GETOPT_H 1 +#define HAVE_FEATURES_H 1 +#define HAVE_ENDIAN_H 1 +#define HAVE_BYTESWAP_H 1 +#define HAVE_SYS_PARAM_H 1 +#define HAVE_SYS_IOCTL_H 1 +#define HAVE_SYS_MOUNT_H 1 +#define HAVE_SYS_STAT_H 1 +#define HAVE_SYS_TYPES_H 1 +#define HAVE_SYS_VFS_H 1 +#define HAVE_SYS_STATVFS_H 1 +#define HAVE_SYS_SYSMACROS_H 1 +#define HAVE_LINUX_MAJOR_H 1 +#define HAVE_LINUX_FD_H 1 +#define HAVE_LINUX_HDREG_H 1 +#define HAVE_SYSLOG_H 1 +#define HAVE__BOOL 1 +#define HAVE_STDBOOL_H 1 +#define WORDS_LITTLEENDIAN 1 +#define HAVE_STRUCT_STAT_ST_BLOCKS 1 +#define HAVE_ST_BLOCKS 1 +#define HAVE_STRUCT_STAT_ST_RDEV 1 +#define HAVE_STRUCT_STAT_ST_ATIMENSEC 1 +#define HAVE_GETMNTENT +#define HAVE_MBRTOWC 1 +#define HAVE_STAT_EMPTY_STRING_BUG 1 +#define HAVE_STRFTIME 1 +#define HAVE_UTIME_H 1 +#define HAVE_VPRINTF 1 +#define HAVE_ATEXIT 1 +#define HAVE_BASENAME 1 +#define HAVE_DAEMON 1 +#define HAVE_DUP2 1 +#define HAVE_FDATASYNC 1 +#define HAVE_FFS 1 +#define HAVE_GETOPT_LONG 1 +#define HAVE_HASMNTOPT 1 +#define HAVE_MBSINIT 1 +#define HAVE_MEMMOVE 1 +#define HAVE_MEMSET 1 +#define HAVE_REALPATH 1 +#define HAVE_REGCOMP 1 +#define HAVE_SETLOCALE 1 +#define HAVE_SETXATTR 1 +#define HAVE_STRCASECMP 1 +#define HAVE_STRCHR 1 +#define HAVE_STRDUP 1 +#define HAVE_STRERROR 1 +#define HAVE_STRNLEN 1 +#define HAVE_STRSEP 1 +#define HAVE_STRTOL 1 +#define HAVE_STRTOUL 1 +#define HAVE_SYSCONF 1 +#define HAVE_UTIME 1 +#define HAVE_GETTIMEOFDAY 1 +#define HAVE_CLOCK_GETTIME 1 +#define HAVE_FORK 1 +#define _FILE_OFFSET_BITS 64 + +configure: exit 0 diff --git a/config.status b/config.status new file mode 100755 index 0000000..aede0bf --- a/dev/null +++ b/config.status @@ -0,0 +1,1220 @@ +#! /bin/bash +# Generated by configure. +# 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-/bin/bash} +## --------------------- ## +## 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=: + # Zsh 3.x and 4.x performs 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 + + + + +# PATH needs CR +# 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 + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi + +# Support unset when possible. +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +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.) +as_nl=' +' +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +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 + echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + { (exit 1); exit 1; } +fi + +# Work around bugs in pre-3.0 UWIN ksh. +for as_var in ENV MAIL MAILPATH +do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +for as_var in \ + LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ + LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ + LC_TELEPHONE LC_TIME +do + if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then + eval $as_var=C; export $as_var + else + ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var + fi +done + +# Required to use basename. +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 + + +# Name of the executable. +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# CDPATH. +$as_unset CDPATH + + + + as_lineno_1=$LINENO + as_lineno_2=$LINENO + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || { + + # Create $as_me.lineno as a copy of $as_myself, but with $LINENO + # uniformly replaced by the line number. The first 'sed' inserts a + # line-number line after each line using $LINENO; the second 'sed' + # does the real work. The second script uses 'N' to pair each + # line-number line with the line containing $LINENO, and appends + # trailing '-' during substitution so that $LINENO is not a special + # case at line end. + # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the + # scripts with optimization help from Paolo Bonzini. 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" || + { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 + { (exit 1); exit 1; }; } + + # 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 +} + + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in +-n*) + case `echo 'x\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + *) ECHO_C='\c';; + esac;; +*) + ECHO_N='-n';; +esac + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +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 +fi +echo >conf$$.file +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 -p'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -p' +elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln +else + as_ln_s='cp -p' +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=: +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +if test -x / >/dev/null 2>&1; then + as_test_x='test -x' +else + if ls -dL / >/dev/null 2>&1; then + as_ls_L_option=L + else + as_ls_L_option= + fi + as_test_x=' + eval sh -c '\'' + if test -d "$1"; then + test -d "$1/."; + else + case $1 in + -*)set "./$1";; + esac; + case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in + ???[sx]*):;;*)false;;esac;fi + '\'' sh + ' +fi +as_executable_p=$as_test_x + +# 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 + +# 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 ntfs-3g $as_me 2010.5.16, which was +generated by GNU Autoconf 2.61. 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` +" + +# Files that config.status was made for. +config_files=" Makefile include/Makefile include/fuse-lite/Makefile include/ntfs-3g/Makefile libfuse-lite/Makefile libntfs-3g/Makefile libntfs-3g/libntfs-3g.pc libntfs-3g/libntfs-3g.script.so src/Makefile src/ntfs-3g.8 src/ntfs-3g.probe.8 src/ntfs-3g.usermap.8 src/ntfs-3g.secaudit.8" +config_headers=" config.h" +config_commands=" depfiles" + +ac_cs_usage="\ +\`$as_me' instantiates files from templates according to the +current configuration. + +Usage: $0 [OPTIONS] [FILE]... + + -h, --help print this help, then exit + -V, --version print version number and configuration settings, then exit + -q, --quiet 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 ." + +ac_cs_version="\ +ntfs-3g config.status 2010.5.16 +configured by ./configure, generated by GNU Autoconf 2.61, + with options \"'CC=arc-linux-uclibc-gcc' '--prefix=/mnt/fileroot/michael.wang/linux-top-pub/ui_ref/trunk/bld_7266_h_64x2/./rootfs' '--host=arc-linux-uclibc' 'CFLAGS=-mA7 -g' '--enable-mount-helper=no' '--enable-ldconfig=no' 'exec_prefix=/mnt/fileroot/michael.wang/linux-top-pub/ui_ref/trunk/bld_7266_h_64x2/./rootfs' 'host_alias=arc-linux-uclibc'\" + +Copyright (C) 2006 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='/mnt/fileroot/michael.wang/linux-top-pub/ui_ref/trunk/build/packages/ntfs-3g-2010.5.16' +srcdir='.' +INSTALL='/usr/bin/install -c' +MKDIR_P='/bin/mkdir -p' +# If no file are specified by the user, then we need to provide default +# value. By we need to know if files were specified by the user. +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=$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 ) + echo "$ac_cs_version"; exit ;; + --debug | --debu | --deb | --de | --d | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + CONFIG_FILES="$CONFIG_FILES $ac_optarg" + ac_need_defaults=false;; + --header | --heade | --head | --hea ) + $ac_shift + CONFIG_HEADERS="$CONFIG_HEADERS $ac_optarg" + ac_need_defaults=false;; + --he | --h) + # Conflict between --help and --header + { echo "$as_me: error: ambiguous option: $1 +Try \`$0 --help' for more information." >&2 + { (exit 1); exit 1; }; };; + --help | --hel | -h ) + 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. + -*) { echo "$as_me: error: unrecognized option: $1 +Try \`$0 --help' for more information." >&2 + { (exit 1); exit 1; }; } ;; + + *) ac_config_targets="$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 + +if $ac_cs_recheck; then + echo "running CONFIG_SHELL=/bin/bash /bin/bash ./configure " 'CC=arc-linux-uclibc-gcc' '--prefix=/mnt/fileroot/michael.wang/linux-top-pub/ui_ref/trunk/bld_7266_h_64x2/./rootfs' '--host=arc-linux-uclibc' 'CFLAGS=-mA7 -g' '--enable-mount-helper=no' '--enable-ldconfig=no' 'exec_prefix=/mnt/fileroot/michael.wang/linux-top-pub/ui_ref/trunk/bld_7266_h_64x2/./rootfs' 'host_alias=arc-linux-uclibc' $ac_configure_extra_args " --no-create --no-recursion" >&6 + CONFIG_SHELL=/bin/bash + export CONFIG_SHELL + exec /bin/bash "./configure" 'CC=arc-linux-uclibc-gcc' '--prefix=/mnt/fileroot/michael.wang/linux-top-pub/ui_ref/trunk/bld_7266_h_64x2/./rootfs' '--host=arc-linux-uclibc' 'CFLAGS=-mA7 -g' '--enable-mount-helper=no' '--enable-ldconfig=no' 'exec_prefix=/mnt/fileroot/michael.wang/linux-top-pub/ui_ref/trunk/bld_7266_h_64x2/./rootfs' 'host_alias=arc-linux-uclibc' $ac_configure_extra_args --no-create --no-recursion +fi + +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX + echo "$ac_log" +} >&5 + +# +# INIT-COMMANDS +# +AMDEP_TRUE="" ac_aux_dir="." + + +# Handling of arguments. +for ac_config_target in $ac_config_targets +do + case $ac_config_target in + "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; + "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; + "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; + "include/Makefile") CONFIG_FILES="$CONFIG_FILES include/Makefile" ;; + "include/fuse-lite/Makefile") CONFIG_FILES="$CONFIG_FILES include/fuse-lite/Makefile" ;; + "include/ntfs-3g/Makefile") CONFIG_FILES="$CONFIG_FILES include/ntfs-3g/Makefile" ;; + "libfuse-lite/Makefile") CONFIG_FILES="$CONFIG_FILES libfuse-lite/Makefile" ;; + "libntfs-3g/Makefile") CONFIG_FILES="$CONFIG_FILES libntfs-3g/Makefile" ;; + "libntfs-3g/libntfs-3g.pc") CONFIG_FILES="$CONFIG_FILES libntfs-3g/libntfs-3g.pc" ;; + "libntfs-3g/libntfs-3g.script.so") CONFIG_FILES="$CONFIG_FILES libntfs-3g/libntfs-3g.script.so" ;; + "src/Makefile") CONFIG_FILES="$CONFIG_FILES src/Makefile" ;; + "src/ntfs-3g.8") CONFIG_FILES="$CONFIG_FILES src/ntfs-3g.8" ;; + "src/ntfs-3g.probe.8") CONFIG_FILES="$CONFIG_FILES src/ntfs-3g.probe.8" ;; + "src/ntfs-3g.usermap.8") CONFIG_FILES="$CONFIG_FILES src/ntfs-3g.usermap.8" ;; + "src/ntfs-3g.secaudit.8") CONFIG_FILES="$CONFIG_FILES src/ntfs-3g.secaudit.8" ;; + + *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5 +echo "$as_me: error: invalid argument: $ac_config_target" >&2;} + { (exit 1); exit 1; }; };; + 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= + trap 'exit_status=$? + { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status +' 0 + trap '{ (exit 1); exit 1; }' 1 2 13 15 +} +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && + test -n "$tmp" && test -d "$tmp" +} || +{ + tmp=./conf$$-$RANDOM + (umask 077 && mkdir "$tmp") +} || +{ + echo "$me: cannot create a temporary directory in ." >&2 + { (exit 1); exit 1; } +} + +# +# Set up the sed scripts for CONFIG_FILES section. +# + +# No need to generate the scripts if there are no CONFIG_FILES. +# This happens for instance when ./config.status config.h +if test -n "$CONFIG_FILES"; then + +cat >"$tmp/subs-1.sed" <<\CEOF +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s,@SHELL@,|#_!!_#|/bin/bash,g +s,@PATH_SEPARATOR@,|#_!!_#|:,g +s,@PACKAGE_NAME@,|#_!!_#|ntfs-3g,g +s,@PACKAGE_TARNAME@,|#_!!_#|ntfs-3g,g +s,@PACKAGE_VERSION@,|#_!!_#|2010.5.16,g +s,@PACKAGE_STRING@,|#_!!_#|ntfs-3g 2010.5.16,g +s,@PACKAGE_BUGREPORT@,|#_!!_#|ntfs-3g-devel@|#_!!_#|lists.sf.net,g +s,@exec_prefix@,|#_!!_#|/mnt/fileroot/michael.wang/linux-top-pub/ui_ref/trunk/bld_7266_h_64x2/./rootfs,g +s,@prefix@,|#_!!_#|/mnt/fileroot/michael.wang/linux-top-pub/ui_ref/trunk/bld_7266_h_64x2/./rootfs,g +s,@program_transform_name@,|#_!!_#|s\,x\,x\,,g +s,@bindir@,|#_!!_#|${exec_prefix}/bin,g +s,@sbindir@,|#_!!_#|${exec_prefix}/sbin,g +s,@libexecdir@,|#_!!_#|${exec_prefix}/libexec,g +s,@datarootdir@,|#_!!_#|${prefix}/share,g +s,@datadir@,|#_!!_#|${datarootdir},g +s,@sysconfdir@,|#_!!_#|${prefix}/etc,g +s,@sharedstatedir@,|#_!!_#|${prefix}/com,g +s,@localstatedir@,|#_!!_#|${prefix}/var,g +s,@includedir@,|#_!!_#|${prefix}/include,g +s,@oldincludedir@,|#_!!_#|/usr/include,g +s,@docdir@,|#_!!_#|${datarootdir}/doc/${PACKAGE_TARNAME},g +s,@infodir@,|#_!!_#|${datarootdir}/info,g +s,@htmldir@,|#_!!_#|${docdir},g +s,@dvidir@,|#_!!_#|${docdir},g +s,@pdfdir@,|#_!!_#|${docdir},g +s,@psdir@,|#_!!_#|${docdir},g +s,@libdir@,|#_!!_#|${exec_prefix}/lib,g +s,@localedir@,|#_!!_#|${datarootdir}/locale,g +s,@mandir@,|#_!!_#|${datarootdir}/man,g +s,@DEFS@,|#_!!_#|-DHAVE_CONFIG_H,g +s,@ECHO_C@,|#_!!_#|,g +s,@ECHO_N@,|#_!!_#|-n,g +s,@ECHO_T@,|#_!!_#|,g +s,@LIBS@,|#_!!_#|,g +s,@build_alias@,|#_!!_#|,g +s,@host_alias@,|#_!!_#|arc-linux-uclibc,g +s,@target_alias@,|#_!!_#|,g +s,@build@,|#_!!_#|i686-pc-linux-gnu,g +s,@build_cpu@,|#_!!_#|i686,g +s,@build_vendor@,|#_!!_#|pc,g +s,@build_os@,|#_!!_#|linux-gnu,g +s,@host@,|#_!!_#|arc-unknown-linux-uclibc,g +s,@host_cpu@,|#_!!_#|arc,g +s,@host_vendor@,|#_!!_#|unknown,g +s,@host_os@,|#_!!_#|linux-uclibc,g +s,@target@,|#_!!_#|arc-unknown-linux-uclibc,g +s,@target_cpu@,|#_!!_#|arc,g +s,@target_vendor@,|#_!!_#|unknown,g +s,@target_os@,|#_!!_#|linux-uclibc,g +s,@INSTALL_PROGRAM@,|#_!!_#|${INSTALL},g +s,@INSTALL_SCRIPT@,|#_!!_#|${INSTALL},g +s,@INSTALL_DATA@,|#_!!_#|${INSTALL} -m 644,g +s,@am__isrc@,|#_!!_#|,g +s,@CYGPATH_W@,|#_!!_#|echo,g +s,@PACKAGE@,|#_!!_#|ntfs-3g,g +s,@VERSION@,|#_!!_#|2010.5.16,g +s,@ACLOCAL@,|#_!!_#|${SHELL} /mnt/fileroot/michael.wang/linux-top-pub/ui_ref/trunk/build/packages/ntfs-3g-2010.5.16/missing --run aclocal-1.10,g +s,@AUTOCONF@,|#_!!_#|${SHELL} /mnt/fileroot/michael.wang/linux-top-pub/ui_ref/trunk/build/packages/ntfs-3g-2010.5.16/missing --run autoconf,g +s,@AUTOMAKE@,|#_!!_#|${SHELL} /mnt/fileroot/michael.wang/linux-top-pub/ui_ref/trunk/build/packages/ntfs-3g-2010.5.16/missing --run automake-1.10,g +s,@AUTOHEADER@,|#_!!_#|${SHELL} /mnt/fileroot/michael.wang/linux-top-pub/ui_ref/trunk/build/packages/ntfs-3g-2010.5.16/missing --run autoheader,g +s,@MAKEINFO@,|#_!!_#|${SHELL} /mnt/fileroot/michael.wang/linux-top-pub/ui_ref/trunk/build/packages/ntfs-3g-2010.5.16/missing --run makeinfo,g +s,@install_sh@,|#_!!_#|$(SHELL) /mnt/fileroot/michael.wang/linux-top-pub/ui_ref/trunk/build/packages/ntfs-3g-2010.5.16/install-sh,g +s,@STRIP@,|#_!!_#|arc-linux-uclibc-strip,g +s,@INSTALL_STRIP_PROGRAM@,|#_!!_#|$(install_sh) -c -s,g +s,@mkdir_p@,|#_!!_#|/bin/mkdir -p,g +s,@AWK@,|#_!!_#|mawk,g +s,@SET_MAKE@,|#_!!_#|,g +s,@am__leading_dot@,|#_!!_#|.,g +s,@AMTAR@,|#_!!_#|${SHELL} /mnt/fileroot/michael.wang/linux-top-pub/ui_ref/trunk/build/packages/ntfs-3g-2010.5.16/missing --run tar,g +s,@am__tar@,|#_!!_#|${AMTAR} chof - "$$tardir",g +s,@am__untar@,|#_!!_#|${AMTAR} xf -,g +s,@MAINTAINER_MODE_TRUE@,|#_!!_#|#,g +s,@MAINTAINER_MODE_FALSE@,|#_!!_#|,g +s,@MAINT@,|#_!!_#|#,g +s,@CC@,|#_!!_#|arc-linux-uclibc-gcc,g +s,@CFLAGS@,|#_!!_#|-mA7 -g -Wall,g +s,@LDFLAGS@,|#_!!_#|,g +s,@CPPFLAGS@,|#_!!_#|,g +s,@ac_ct_CC@,|#_!!_#|,g +s,@EXEEXT@,|#_!!_#|,g +s,@OBJEXT@,|#_!!_#|o,g +s,@DEPDIR@,|#_!!_#|.deps,g +s,@am__include@,|#_!!_#|include,g +s,@am__quote@,|#_!!_#|,g +s,@AMDEP_TRUE@,|#_!!_#|,g +s,@AMDEP_FALSE@,|#_!!_#|#,g +s,@AMDEPBACKSLASH@,|#_!!_#|\\,g +s,@CCDEPMODE@,|#_!!_#|depmode=gcc3,g +s,@am__fastdepCC_TRUE@,|#_!!_#|,g +s,@am__fastdepCC_FALSE@,|#_!!_#|#,g +s,@LN_S@,|#_!!_#|ln -s,g +s,@SED@,|#_!!_#|/bin/sed,g +s,@GREP@,|#_!!_#|/bin/grep,g +s,@EGREP@,|#_!!_#|/bin/grep -E,g +s,@ECHO@,|#_!!_#|echo,g +s,@AR@,|#_!!_#|arc-linux-uclibc-ar,g +s,@RANLIB@,|#_!!_#|arc-linux-uclibc-ranlib,g +CEOF +cat >"$tmp/subs-2.sed" <<\CEOF +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b end +s,@DSYMUTIL@,|#_!!_#|,g +s,@NMEDIT@,|#_!!_#|,g +s,@CPP@,|#_!!_#|arc-linux-uclibc-gcc -E,g +s,@CXX@,|#_!!_#|arc-linux-uclibc-g++,g +s,@CXXFLAGS@,|#_!!_#|-g -O2,g +s,@ac_ct_CXX@,|#_!!_#|,g +s,@CXXDEPMODE@,|#_!!_#|depmode=gcc3,g +s,@am__fastdepCXX_TRUE@,|#_!!_#|,g +s,@am__fastdepCXX_FALSE@,|#_!!_#|#,g +s,@CXXCPP@,|#_!!_#|arc-linux-uclibc-g++ -E,g +s,@F77@,|#_!!_#|,g +s,@FFLAGS@,|#_!!_#|,g +s,@ac_ct_F77@,|#_!!_#|,g +s,@LIBTOOL@,|#_!!_#|$(SHELL) $(top_builddir)/libtool,g +s,@MV@,|#_!!_#|/bin/mv,g +s,@RM@,|#_!!_#|/bin/rm,g +s,@LDCONFIG@,|#_!!_#|/sbin/ldconfig,g +s,@PKG_CONFIG@,|#_!!_#|,g +s,@FUSE_MODULE_CFLAGS@,|#_!!_#|,g +s,@FUSE_MODULE_LIBS@,|#_!!_#|,g +s,@LIBOBJS@,|#_!!_#| ${LIBOBJDIR}memcmp$U.o ${LIBOBJDIR}lstat$U.o ${LIBOBJDIR}stat$U.o,g +s,@pkgconfigdir@,|#_!!_#|$(libdir)/pkgconfig,g +s,@ntfs3gincludedir@,|#_!!_#|$(includedir)/ntfs-3g,g +s,@rootbindir@,|#_!!_#|$(bindir),g +s,@rootsbindir@,|#_!!_#|$(sbindir),g +s,@rootlibdir@,|#_!!_#|$(libdir),g +s,@LIBNTFS_3G_VERSION@,|#_!!_#|76,g +s,@LIBFUSE_LITE_LIBS@,|#_!!_#| -lpthread,g +s,@OUTPUT_FORMAT@,|#_!!_#|,g +s,@FUSE_INTERNAL_TRUE@,|#_!!_#|,g +s,@FUSE_INTERNAL_FALSE@,|#_!!_#|#,g +s,@GENERATE_LDSCRIPT_TRUE@,|#_!!_#|#,g +s,@GENERATE_LDSCRIPT_FALSE@,|#_!!_#|,g +s,@WINDOWS_TRUE@,|#_!!_#|#,g +s,@WINDOWS_FALSE@,|#_!!_#|,g +s,@NTFS_DEVICE_DEFAULT_IO_OPS_TRUE@,|#_!!_#|,g +s,@NTFS_DEVICE_DEFAULT_IO_OPS_FALSE@,|#_!!_#|#,g +s,@RUN_LDCONFIG_TRUE@,|#_!!_#|#,g +s,@RUN_LDCONFIG_FALSE@,|#_!!_#|,g +s,@REALLYSTATIC_TRUE@,|#_!!_#|#,g +s,@REALLYSTATIC_FALSE@,|#_!!_#|,g +s,@INSTALL_LIBRARY_TRUE@,|#_!!_#|,g +s,@INSTALL_LIBRARY_FALSE@,|#_!!_#|#,g +s,@ENABLE_MOUNT_HELPER_TRUE@,|#_!!_#|#,g +s,@ENABLE_MOUNT_HELPER_FALSE@,|#_!!_#|,g +s,@MKDIR_P@,|#_!!_#|/bin/mkdir -p,g +s,@LTLIBOBJS@,|#_!!_#| ${LIBOBJDIR}memcmp$U.lo ${LIBOBJDIR}lstat$U.lo ${LIBOBJDIR}stat$U.lo,g +:end +s/|#_!!_#|//g +CEOF +fi # test -n "$CONFIG_FILES" + + +for ac_tag in :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS +do + case $ac_tag in + :[FHLC]) ac_mode=$ac_tag; continue;; + esac + case $ac_mode$ac_tag in + :[FHL]*:*);; + :L* | :C*:*) { { echo "$as_me:$LINENO: error: Invalid tag $ac_tag." >&5 +echo "$as_me: error: Invalid tag $ac_tag." >&2;} + { (exit 1); exit 1; }; };; + :[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="$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 || + { { echo "$as_me:$LINENO: error: cannot find input file: $ac_f" >&5 +echo "$as_me: error: cannot find input file: $ac_f" >&2;} + { (exit 1); exit 1; }; };; + esac + ac_file_inputs="$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 "`IFS=: + echo $* | sed 's|^[^:]*/||;s|:[^:]*/|, |g'`" by configure." + if test x"$ac_file" != x-; then + configure_input="$ac_file. $configure_input" + { echo "$as_me:$LINENO: creating $ac_file" >&5 +echo "$as_me: creating $ac_file" >&6;} + fi + + case $ac_tag in + *:-:* | *:-) cat >"$tmp/stdin";; + 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 || +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" + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || { $as_mkdir_p && mkdir -p "$as_dir"; } || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`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 || +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" || { { echo "$as_me:$LINENO: error: cannot create directory $as_dir" >&5 +echo "$as_me: error: cannot create directory $as_dir" >&2;} + { (exit 1); exit 1; }; }; } + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`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 +# 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= + +case `sed -n '/datarootdir/ { + p + q +} +/@datadir@/p +/@docdir@/p +/@infodir@/p +/@localedir@/p +/@mandir@/p +' $ac_file_inputs` in +*datarootdir*) ac_datarootdir_seen=yes;; +*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) + { echo "$as_me:$LINENO: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} + ac_datarootdir_hack=' + s&@datadir@&${datarootdir}&g + s&@docdir@&${datarootdir}/doc/${PACKAGE_TARNAME}&g + s&@infodir@&${datarootdir}/info&g + s&@localedir@&${datarootdir}/locale&g + s&@mandir@&${datarootdir}/man&g + s&\${datarootdir}&${prefix}/share&g' ;; +esac + sed "/^[ ]*VPATH[ ]*=/{ +s/:*\$(srcdir):*/:/ +s/:*\${srcdir}:*/:/ +s/:*@srcdir@:*/:/ +s/^\([^=]*=[ ]*\):*/\1/ +s/:*$// +s/^[^=]*=[ ]*$// +} + +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s&@configure_input@&$configure_input&;t t +s&@top_builddir@&$ac_top_builddir_sub&;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 +" $ac_file_inputs | sed -f "$tmp/subs-1.sed" | sed -f "$tmp/subs-2.sed" >$tmp/out + +test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && + { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } && + { echo "$as_me:$LINENO: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined." >&5 +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 "$tmp/stdin" + case $ac_file in + -) cat "$tmp/out"; rm -f "$tmp/out";; + *) rm -f "$ac_file"; mv "$tmp/out" $ac_file;; + esac + ;; + :H) + # + # CONFIG_HEADER + # + # First, check the format of the line: + cat >"$tmp/defines.sed" <<\CEOF +/^[ ]*#[ ]*undef[ ][ ]*[_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ][_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789]*[ ]*$/b def +/^[ ]*#[ ]*define[ ][ ]*[_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ][_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789]*[( ]/b def +b +:def +s/$/ / +s,^\([ #]*\)[^ ]*\([ ]*PACKAGE_NAME\)[ (].*,\1define\2 "ntfs-3g" , +s,^\([ #]*\)[^ ]*\([ ]*PACKAGE_TARNAME\)[ (].*,\1define\2 "ntfs-3g" , +s,^\([ #]*\)[^ ]*\([ ]*PACKAGE_VERSION\)[ (].*,\1define\2 "2010.5.16" , +s,^\([ #]*\)[^ ]*\([ ]*PACKAGE_STRING\)[ (].*,\1define\2 "ntfs-3g 2010.5.16" , +s,^\([ #]*\)[^ ]*\([ ]*PACKAGE_BUGREPORT\)[ (].*,\1define\2 "ntfs-3g-devel@lists.sf.net" , +s,^\([ #]*\)[^ ]*\([ ]*PACKAGE\)[ (].*,\1define\2 "ntfs-3g" , +s,^\([ #]*\)[^ ]*\([ ]*VERSION\)[ (].*,\1define\2 "2010.5.16" , +s,^\([ #]*\)[^ ]*\([ ]*_GNU_SOURCE\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*STDC_HEADERS\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*HAVE_SYS_TYPES_H\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*HAVE_SYS_STAT_H\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*HAVE_STDLIB_H\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*HAVE_STRING_H\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*HAVE_MEMORY_H\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*HAVE_STRINGS_H\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*HAVE_INTTYPES_H\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*HAVE_STDINT_H\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*HAVE_UNISTD_H\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*HAVE_DLFCN_H\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*_REENTRANT\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*FUSE_INTERNAL\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*STDC_HEADERS\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*HAVE_CTYPE_H\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*HAVE_FCNTL_H\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*HAVE_LIBGEN_H\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*HAVE_LIMITS_H\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*HAVE_LOCALE_H\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*HAVE_MNTENT_H\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*HAVE_STDDEF_H\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*HAVE_STDINT_H\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*HAVE_STDLIB_H\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*HAVE_STDIO_H\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*HAVE_STDARG_H\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*HAVE_STRING_H\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*HAVE_STRINGS_H\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*HAVE_ERRNO_H\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*HAVE_TIME_H\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*HAVE_UNISTD_H\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*HAVE_UTIME_H\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*HAVE_WCHAR_H\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*HAVE_GETOPT_H\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*HAVE_FEATURES_H\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*HAVE_ENDIAN_H\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*HAVE_BYTESWAP_H\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*HAVE_SYS_PARAM_H\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*HAVE_SYS_IOCTL_H\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*HAVE_SYS_MOUNT_H\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*HAVE_SYS_STAT_H\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*HAVE_SYS_TYPES_H\)[ (].*,\1define\2 1 , +CEOF + sed -f "$tmp/defines.sed" $ac_file_inputs >"$tmp/out1" + # First, check the format of the line: + cat >"$tmp/defines.sed" <<\CEOF +/^[ ]*#[ ]*undef[ ][ ]*[_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ][_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789]*[ ]*$/b def +/^[ ]*#[ ]*define[ ][ ]*[_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ][_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789]*[( ]/b def +b +:def +s,^\([ #]*\)[^ ]*\([ ]*HAVE_SYS_VFS_H\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*HAVE_SYS_STATVFS_H\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*HAVE_SYS_SYSMACROS_H\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*HAVE_LINUX_MAJOR_H\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*HAVE_LINUX_FD_H\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*HAVE_LINUX_HDREG_H\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*HAVE_SYSLOG_H\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*HAVE__BOOL\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*HAVE_STDBOOL_H\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*WORDS_LITTLEENDIAN\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*HAVE_STRUCT_STAT_ST_BLOCKS\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*HAVE_ST_BLOCKS\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*HAVE_STRUCT_STAT_ST_RDEV\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*HAVE_STRUCT_STAT_ST_ATIMENSEC\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*HAVE_GETMNTENT\)[ (].*,\1define\2 , +s,^\([ #]*\)[^ ]*\([ ]*HAVE_MBRTOWC\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*HAVE_STAT_EMPTY_STRING_BUG\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*HAVE_STRFTIME\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*HAVE_UTIME_H\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*HAVE_VPRINTF\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*HAVE_ATEXIT\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*HAVE_BASENAME\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*HAVE_DAEMON\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*HAVE_DUP2\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*HAVE_FDATASYNC\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*HAVE_FFS\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*HAVE_GETOPT_LONG\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*HAVE_HASMNTOPT\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*HAVE_MBSINIT\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*HAVE_MEMMOVE\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*HAVE_MEMSET\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*HAVE_REALPATH\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*HAVE_REGCOMP\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*HAVE_SETLOCALE\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*HAVE_SETXATTR\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*HAVE_STRCASECMP\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*HAVE_STRCHR\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*HAVE_STRDUP\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*HAVE_STRERROR\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*HAVE_STRNLEN\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*HAVE_STRSEP\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*HAVE_STRTOL\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*HAVE_STRTOUL\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*HAVE_SYSCONF\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*HAVE_UTIME\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*HAVE_GETTIMEOFDAY\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*HAVE_CLOCK_GETTIME\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*HAVE_FORK\)[ (].*,\1define\2 1 , +s,^\([ #]*\)[^ ]*\([ ]*_FILE_OFFSET_BITS\)[ (].*,\1define\2 64 , +s/ $// +CEOF + sed -f "$tmp/defines.sed" "$tmp/out1" >"$tmp/out2" + # First, check the format of the line: + cat >"$tmp/defines.sed" <<\CEOF +/^[ ]*#[ ]*undef[ ][ ]*[_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ][_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789]*[ ]*$/b def +/^[ ]*#[ ]*define[ ][ ]*[_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ][_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789]*[( ]/b def +b +:def +s,^[ #]*u.*,/* & */, +CEOF + sed -f "$tmp/defines.sed" "$tmp/out2" >"$tmp/out1" +ac_result="$tmp/out1" + if test x"$ac_file" != x-; then + echo "/* $configure_input */" >"$tmp/config.h" + cat "$ac_result" >>"$tmp/config.h" + if diff $ac_file "$tmp/config.h" >/dev/null 2>&1; then + { echo "$as_me:$LINENO: $ac_file is unchanged" >&5 +echo "$as_me: $ac_file is unchanged" >&6;} + else + rm -f $ac_file + mv "$tmp/config.h" $ac_file + fi + else + echo "/* $configure_input */" + cat "$ac_result" + fi + rm -f "$tmp/out12" +# 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 || +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) { echo "$as_me:$LINENO: executing $ac_file commands" >&5 +echo "$as_me: executing $ac_file commands" >&6;} + ;; + esac + + + case $ac_file$ac_mode in + "depfiles":C) test x"$AMDEP_TRUE" != x"" || for mf in $CONFIG_FILES; do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named `Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # Grep'ing the whole file is not good either: AIX grep has a line + # limit of 2048, but all sed's we know have understand at least 4000. + if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then + dirpart=`$as_dirname -- "$mf" || +$as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$mf" : 'X\(//\)[^/]' \| \ + X"$mf" : 'X\(//\)$' \| \ + X"$mf" : 'X\(/\)' \| . 2>/dev/null || +echo X"$mf" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + else + continue + fi + # Extract the definition of DEPDIR, am__include, and am__quote + # from the Makefile without running `make'. + DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` + test -z "$DEPDIR" && continue + am__include=`sed -n 's/^am__include = //p' < "$mf"` + test -z "am__include" && continue + am__quote=`sed -n 's/^am__quote = //p' < "$mf"` + # When using ansi2knr, U may be empty or an underscore; expand it + U=`sed -n 's/^U = //p' < "$mf"` + # Find all dependency output files, they are included files with + # $(DEPDIR) in their names. We invoke sed twice because it is the + # simplest approach to changing $(DEPDIR) to its actual value in the + # expansion. + for file in `sed -n " + s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`$as_dirname -- "$file" || +$as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$file" : 'X\(//\)[^/]' \| \ + X"$file" : 'X\(//\)$' \| \ + X"$file" : 'X\(/\)' \| . 2>/dev/null || +echo X"$file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + { as_dir=$dirpart/$fdir + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || { $as_mkdir_p && mkdir -p "$as_dir"; } || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`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 || +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" || { { echo "$as_me:$LINENO: error: cannot create directory $as_dir" >&5 +echo "$as_me: error: cannot create directory $as_dir" >&2;} + { (exit 1); exit 1; }; }; } + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done +done + ;; + + esac +done # for ac_tag + + +{ (exit 0); exit 0; } diff --git a/config.sub b/config.sub new file mode 100755 index 0000000..6759825 --- a/dev/null +++ b/config.sub @@ -0,0 +1,1658 @@ +#! /bin/sh +# Configuration validation subroutine script. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 +# Free Software Foundation, Inc. + +timestamp='2008-01-16' + +# This file is (in principle) common to ALL GNU software. +# The presence of a machine in this file suggests that SOME GNU software +# can handle that machine. It does not imply ALL GNU software can. +# +# This file is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA +# 02110-1301, USA. +# +# 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. + + +# Please send patches to . Submit a context +# diff and a properly formatted ChangeLog entry. +# +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# Otherwise, we print the canonical config type on stdout and succeed. + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or in some cases, the newer four-part form: +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] CPU-MFR-OPSYS + $0 [OPTION] ALIAS + +Canonicalize a configuration name. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.sub ($timestamp) + +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, +2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" + exit 1 ;; + + *local*) + # First pass through any local machine types. + echo $1 + exit ;; + + * ) + break ;; + esac +done + +case $# in + 0) echo "$me: missing argument$help" >&2 + exit 1;; + 1) ;; + *) echo "$me: too many arguments$help" >&2 + exit 1;; +esac + +# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). +# Here we must recognize all the valid KERNEL-OS combinations. +maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` +case $maybe_os in + nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \ + uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \ + storm-chaos* | os2-emx* | rtmk-nova*) + os=-$maybe_os + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` + ;; + *) + basic_machine=`echo $1 | sed 's/-[^-]*$//'` + if [ $basic_machine != $1 ] + then os=`echo $1 | sed 's/.*-/-/'` + else os=; fi + ;; +esac + +### Let's recognize common machines as not being operating systems so +### that things like config.sub decstation-3100 work. We also +### recognize some manufacturers as not being operating systems, so we +### can provide default operating systems below. +case $os in + -sun*os*) + # Prevent following clause from handling this invalid input. + ;; + -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ + -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ + -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ + -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ + -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ + -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ + -apple | -axis | -knuth | -cray) + os= + basic_machine=$1 + ;; + -sim | -cisco | -oki | -wec | -winbond) + os= + basic_machine=$1 + ;; + -scout) + ;; + -wrs) + os=-vxworks + basic_machine=$1 + ;; + -chorusos*) + os=-chorusos + basic_machine=$1 + ;; + -chorusrdb) + os=-chorusrdb + basic_machine=$1 + ;; + -hiux*) + os=-hiuxwe2 + ;; + -sco6) + os=-sco5v6 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5) + os=-sco3.2v5 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco4) + os=-sco3.2v4 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2.[4-9]*) + os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2v[4-9]*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5v6*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco*) + os=-sco3.2v2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -udk*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -isc) + os=-isc2.2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -clix*) + basic_machine=clipper-intergraph + ;; + -isc*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -lynx*) + os=-lynxos + ;; + -ptx*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` + ;; + -windowsnt*) + os=`echo $os | sed -e 's/windowsnt/winnt/'` + ;; + -psos*) + os=-psos + ;; + -mint | -mint[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; +esac + +# Decode aliases for certain CPU-COMPANY combinations. +case $basic_machine in + # Recognize the basic CPU types without company name. + # Some are omitted here because they have special meanings below. + 1750a | 580 \ + | a29k \ + | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ + | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ + | am33_2.0 \ + | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \ + | bfin \ + | c4x | clipper \ + | d10v | d30v | dlx | dsp16xx \ + | fido | fr30 | frv \ + | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ + | i370 | i860 | i960 | ia64 \ + | ip2k | iq2000 \ + | m32c | m32r | m32rle | m68000 | m68k | m88k \ + | maxq | mb | microblaze | mcore | mep \ + | mips | mipsbe | mipseb | mipsel | mipsle \ + | mips16 \ + | mips64 | mips64el \ + | mips64vr | mips64vrel \ + | mips64orion | mips64orionel \ + | mips64vr4100 | mips64vr4100el \ + | mips64vr4300 | mips64vr4300el \ + | mips64vr5000 | mips64vr5000el \ + | mips64vr5900 | mips64vr5900el \ + | mipsisa32 | mipsisa32el \ + | mipsisa32r2 | mipsisa32r2el \ + | mipsisa64 | mipsisa64el \ + | mipsisa64r2 | mipsisa64r2el \ + | mipsisa64sb1 | mipsisa64sb1el \ + | mipsisa64sr71k | mipsisa64sr71kel \ + | mipstx39 | mipstx39el \ + | mn10200 | mn10300 \ + | mt \ + | msp430 \ + | nios | nios2 \ + | ns16k | ns32k \ + | or32 \ + | pdp10 | pdp11 | pj | pjl \ + | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ + | pyramid \ + | score \ + | sh | sh[1234] | sh[24]a | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ + | sh64 | sh64le \ + | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ + | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ + | spu | strongarm \ + | tahoe | thumb | tic4x | tic80 | tron \ + | v850 | v850e \ + | we32k \ + | x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \ + | z8k) + basic_machine=$basic_machine-unknown + ;; + m6811 | m68hc11 | m6812 | m68hc12) + # Motorola 68HC11/12. + basic_machine=$basic_machine-unknown + os=-none + ;; + m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) + ;; + ms1) + basic_machine=mt-unknown + ;; + + # We use `pc' rather than `unknown' + # because (1) that's what they normally are, and + # (2) the word "unknown" tends to confuse beginning users. + i*86 | x86_64) + basic_machine=$basic_machine-pc + ;; + # Object if more than one company name word. + *-*-*) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; + # Recognize the basic CPU types with company name. + 580-* \ + | a29k-* \ + | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ + | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ + | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ + | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ + | avr-* | avr32-* \ + | bfin-* | bs2000-* \ + | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ + | clipper-* | craynv-* | cydra-* \ + | d10v-* | d30v-* | dlx-* \ + | elxsi-* \ + | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ + | h8300-* | h8500-* \ + | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ + | i*86-* | i860-* | i960-* | ia64-* \ + | ip2k-* | iq2000-* \ + | m32c-* | m32r-* | m32rle-* \ + | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ + | m88110-* | m88k-* | maxq-* | mcore-* \ + | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ + | mips16-* \ + | mips64-* | mips64el-* \ + | mips64vr-* | mips64vrel-* \ + | mips64orion-* | mips64orionel-* \ + | mips64vr4100-* | mips64vr4100el-* \ + | mips64vr4300-* | mips64vr4300el-* \ + | mips64vr5000-* | mips64vr5000el-* \ + | mips64vr5900-* | mips64vr5900el-* \ + | mipsisa32-* | mipsisa32el-* \ + | mipsisa32r2-* | mipsisa32r2el-* \ + | mipsisa64-* | mipsisa64el-* \ + | mipsisa64r2-* | mipsisa64r2el-* \ + | mipsisa64sb1-* | mipsisa64sb1el-* \ + | mipsisa64sr71k-* | mipsisa64sr71kel-* \ + | mipstx39-* | mipstx39el-* \ + | mmix-* \ + | mt-* \ + | msp430-* \ + | nios-* | nios2-* \ + | none-* | np1-* | ns16k-* | ns32k-* \ + | orion-* \ + | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ + | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ + | pyramid-* \ + | romp-* | rs6000-* \ + | sh-* | sh[1234]-* | sh[24]a-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ + | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ + | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ + | sparclite-* \ + | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \ + | tahoe-* | thumb-* \ + | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ + | tron-* \ + | v850-* | v850e-* | vax-* \ + | we32k-* \ + | x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \ + | xstormy16-* | xtensa*-* \ + | ymp-* \ + | z8k-*) + ;; + # Recognize the basic CPU types without company name, with glob match. + xtensa*) + basic_machine=$basic_machine-unknown + ;; + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 386bsd) + basic_machine=i386-unknown + os=-bsd + ;; + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + basic_machine=m68000-att + ;; + 3b*) + basic_machine=we32k-att + ;; + a29khif) + basic_machine=a29k-amd + os=-udi + ;; + abacus) + basic_machine=abacus-unknown + ;; + adobe68k) + basic_machine=m68010-adobe + os=-scout + ;; + alliant | fx80) + basic_machine=fx80-alliant + ;; + altos | altos3068) + basic_machine=m68k-altos + ;; + am29k) + basic_machine=a29k-none + os=-bsd + ;; + amd64) + basic_machine=x86_64-pc + ;; + amd64-*) + basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + amdahl) + basic_machine=580-amdahl + os=-sysv + ;; + amiga | amiga-*) + basic_machine=m68k-unknown + ;; + amigaos | amigados) + basic_machine=m68k-unknown + os=-amigaos + ;; + amigaunix | amix) + basic_machine=m68k-unknown + os=-sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=-sysv + ;; + apollo68bsd) + basic_machine=m68k-apollo + os=-bsd + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + blackfin) + basic_machine=bfin-unknown + os=-linux + ;; + blackfin-*) + basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + c90) + basic_machine=c90-cray + os=-unicos + ;; + convex-c1) + basic_machine=c1-convex + os=-bsd + ;; + convex-c2) + basic_machine=c2-convex + os=-bsd + ;; + convex-c32) + basic_machine=c32-convex + os=-bsd + ;; + convex-c34) + basic_machine=c34-convex + os=-bsd + ;; + convex-c38) + basic_machine=c38-convex + os=-bsd + ;; + cray | j90) + basic_machine=j90-cray + os=-unicos + ;; + craynv) + basic_machine=craynv-cray + os=-unicosmp + ;; + cr16) + basic_machine=cr16-unknown + os=-elf + ;; + crds | unos) + basic_machine=m68k-crds + ;; + crisv32 | crisv32-* | etraxfs*) + basic_machine=crisv32-axis + ;; + cris | cris-* | etrax*) + basic_machine=cris-axis + ;; + crx) + basic_machine=crx-unknown + os=-elf + ;; + da30 | da30-*) + basic_machine=m68k-da30 + ;; + decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) + basic_machine=mips-dec + ;; + decsystem10* | dec10*) + basic_machine=pdp10-dec + os=-tops10 + ;; + decsystem20* | dec20*) + basic_machine=pdp10-dec + os=-tops20 + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + basic_machine=m68k-motorola + ;; + delta88) + basic_machine=m88k-motorola + os=-sysv3 + ;; + djgpp) + basic_machine=i586-pc + os=-msdosdjgpp + ;; + dpx20 | dpx20-*) + basic_machine=rs6000-bull + os=-bosx + ;; + dpx2* | dpx2*-bull) + basic_machine=m68k-bull + os=-sysv3 + ;; + ebmon29k) + basic_machine=a29k-amd + os=-ebmon + ;; + elxsi) + basic_machine=elxsi-elxsi + os=-bsd + ;; + encore | umax | mmax) + basic_machine=ns32k-encore + ;; + es1800 | OSE68k | ose68k | ose | OSE) + basic_machine=m68k-ericsson + os=-ose + ;; + fx2800) + basic_machine=i860-alliant + ;; + genix) + basic_machine=ns32k-ns + ;; + gmicro) + basic_machine=tron-gmicro + os=-sysv + ;; + go32) + basic_machine=i386-pc + os=-go32 + ;; + h3050r* | hiux*) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + h8300hms) + basic_machine=h8300-hitachi + os=-hms + ;; + h8300xray) + basic_machine=h8300-hitachi + os=-xray + ;; + h8500hms) + basic_machine=h8500-hitachi + os=-hms + ;; + harris) + basic_machine=m88k-harris + os=-sysv3 + ;; + hp300-*) + basic_machine=m68k-hp + ;; + hp300bsd) + basic_machine=m68k-hp + os=-bsd + ;; + hp300hpux) + basic_machine=m68k-hp + os=-hpux + ;; + hp3k9[0-9][0-9] | hp9[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + basic_machine=m68000-hp + ;; + hp9k3[2-9][0-9]) + basic_machine=m68k-hp + ;; + hp9k6[0-9][0-9] | hp6[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k7[0-79][0-9] | hp7[0-79][0-9]) + basic_machine=hppa1.1-hp + ;; + hp9k78[0-9] | hp78[0-9]) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][13679] | hp8[0-9][13679]) + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hppa-next) + os=-nextstep3 + ;; + hppaosf) + basic_machine=hppa1.1-hp + os=-osf + ;; + hppro) + basic_machine=hppa1.1-hp + os=-proelf + ;; + i370-ibm* | ibm*) + basic_machine=i370-ibm + ;; +# I'm not sure what "Sysv32" means. Should this be sysv3.2? + i*86v32) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv32 + ;; + i*86v4*) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv4 + ;; + i*86v) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv + ;; + i*86sol2) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-solaris2 + ;; + i386mach) + basic_machine=i386-mach + os=-mach + ;; + i386-vsta | vsta) + basic_machine=i386-unknown + os=-vsta + ;; + iris | iris4d) + basic_machine=mips-sgi + case $os in + -irix*) + ;; + *) + os=-irix4 + ;; + esac + ;; + isi68 | isi) + basic_machine=m68k-isi + os=-sysv + ;; + m68knommu) + basic_machine=m68k-unknown + os=-linux + ;; + m68knommu-*) + basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + m88k-omron*) + basic_machine=m88k-omron + ;; + magnum | m3230) + basic_machine=mips-mips + os=-sysv + ;; + merlin) + basic_machine=ns32k-utek + os=-sysv + ;; + mingw32) + basic_machine=i386-pc + os=-mingw32 + ;; + mingw32ce) + basic_machine=arm-unknown + os=-mingw32ce + ;; + miniframe) + basic_machine=m68000-convergent + ;; + *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; + mips3*-*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` + ;; + mips3*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown + ;; + monitor) + basic_machine=m68k-rom68k + os=-coff + ;; + morphos) + basic_machine=powerpc-unknown + os=-morphos + ;; + msdos) + basic_machine=i386-pc + os=-msdos + ;; + ms1-*) + basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` + ;; + mvs) + basic_machine=i370-ibm + os=-mvs + ;; + ncr3000) + basic_machine=i486-ncr + os=-sysv4 + ;; + netbsd386) + basic_machine=i386-unknown + os=-netbsd + ;; + netwinder) + basic_machine=armv4l-rebel + os=-linux + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + os=-newsos + ;; + news1000) + basic_machine=m68030-sony + os=-newsos + ;; + news-3600 | risc-news) + basic_machine=mips-sony + os=-newsos + ;; + necv70) + basic_machine=v70-nec + os=-sysv + ;; + next | m*-next ) + basic_machine=m68k-next + case $os in + -nextstep* ) + ;; + -ns2*) + os=-nextstep2 + ;; + *) + os=-nextstep3 + ;; + esac + ;; + nh3000) + basic_machine=m68k-harris + os=-cxux + ;; + nh[45]000) + basic_machine=m88k-harris + os=-cxux + ;; + nindy960) + basic_machine=i960-intel + os=-nindy + ;; + mon960) + basic_machine=i960-intel + os=-mon960 + ;; + nonstopux) + basic_machine=mips-compaq + os=-nonstopux + ;; + np1) + basic_machine=np1-gould + ;; + nsr-tandem) + basic_machine=nsr-tandem + ;; + op50n-* | op60c-*) + basic_machine=hppa1.1-oki + os=-proelf + ;; + openrisc | openrisc-*) + basic_machine=or32-unknown + ;; + os400) + basic_machine=powerpc-ibm + os=-os400 + ;; + OSE68000 | ose68000) + basic_machine=m68000-ericsson + os=-ose + ;; + os68k) + basic_machine=m68k-none + os=-os68k + ;; + pa-hitachi) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + paragon) + basic_machine=i860-intel + os=-osf + ;; + parisc) + basic_machine=hppa-unknown + os=-linux + ;; + parisc-*) + basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + pbd) + basic_machine=sparc-tti + ;; + pbb) + basic_machine=m68k-tti + ;; + pc532 | pc532-*) + basic_machine=ns32k-pc532 + ;; + pc98) + basic_machine=i386-pc + ;; + pc98-*) + basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium | p5 | k5 | k6 | nexgen | viac3) + basic_machine=i586-pc + ;; + pentiumpro | p6 | 6x86 | athlon | athlon_*) + basic_machine=i686-pc + ;; + pentiumii | pentium2 | pentiumiii | pentium3) + basic_machine=i686-pc + ;; + pentium4) + basic_machine=i786-pc + ;; + pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) + basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumpro-* | p6-* | 6x86-* | athlon-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium4-*) + basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pn) + basic_machine=pn-gould + ;; + power) basic_machine=power-ibm + ;; + ppc) basic_machine=powerpc-unknown + ;; + ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppcle | powerpclittle | ppc-le | powerpc-little) + basic_machine=powerpcle-unknown + ;; + ppcle-* | powerpclittle-*) + basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64) basic_machine=powerpc64-unknown + ;; + ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64le | powerpc64little | ppc64-le | powerpc64-little) + basic_machine=powerpc64le-unknown + ;; + ppc64le-* | powerpc64little-*) + basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ps2) + basic_machine=i386-ibm + ;; + pw32) + basic_machine=i586-unknown + os=-pw32 + ;; + rdos) + basic_machine=i386-pc + os=-rdos + ;; + rom68k) + basic_machine=m68k-rom68k + os=-coff + ;; + rm[46]00) + basic_machine=mips-siemens + ;; + rtpc | rtpc-*) + basic_machine=romp-ibm + ;; + s390 | s390-*) + basic_machine=s390-ibm + ;; + s390x | s390x-*) + basic_machine=s390x-ibm + ;; + sa29200) + basic_machine=a29k-amd + os=-udi + ;; + sb1) + basic_machine=mipsisa64sb1-unknown + ;; + sb1el) + basic_machine=mipsisa64sb1el-unknown + ;; + sde) + basic_machine=mipsisa32-sde + os=-elf + ;; + sei) + basic_machine=mips-sei + os=-seiux + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + sh5el) + basic_machine=sh5le-unknown + ;; + sh64) + basic_machine=sh64-unknown + ;; + sparclite-wrs | simso-wrs) + basic_machine=sparclite-wrs + os=-vxworks + ;; + sps7) + basic_machine=m68k-bull + os=-sysv2 + ;; + spur) + basic_machine=spur-unknown + ;; + st2000) + basic_machine=m68k-tandem + ;; + stratus) + basic_machine=i860-stratus + os=-sysv4 + ;; + sun2) + basic_machine=m68000-sun + ;; + sun2os3) + basic_machine=m68000-sun + os=-sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + os=-sunos4 + ;; + sun3os3) + basic_machine=m68k-sun + os=-sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + os=-sunos4 + ;; + sun4os3) + basic_machine=sparc-sun + os=-sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + os=-sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + os=-solaris2 + ;; + sun3 | sun3-*) + basic_machine=m68k-sun + ;; + sun4) + basic_machine=sparc-sun + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + ;; + sv1) + basic_machine=sv1-cray + os=-unicos + ;; + symmetry) + basic_machine=i386-sequent + os=-dynix + ;; + t3e) + basic_machine=alphaev5-cray + os=-unicos + ;; + t90) + basic_machine=t90-cray + os=-unicos + ;; + tic54x | c54x*) + basic_machine=tic54x-unknown + os=-coff + ;; + tic55x | c55x*) + basic_machine=tic55x-unknown + os=-coff + ;; + tic6x | c6x*) + basic_machine=tic6x-unknown + os=-coff + ;; + tile*) + basic_machine=tile-unknown + os=-linux-gnu + ;; + tx39) + basic_machine=mipstx39-unknown + ;; + tx39el) + basic_machine=mipstx39el-unknown + ;; + toad1) + basic_machine=pdp10-xkl + os=-tops20 + ;; + tower | tower-32) + basic_machine=m68k-ncr + ;; + tpf) + basic_machine=s390x-ibm + os=-tpf + ;; + udi29k) + basic_machine=a29k-amd + os=-udi + ;; + ultra3) + basic_machine=a29k-nyu + os=-sym1 + ;; + v810 | necv810) + basic_machine=v810-nec + os=-none + ;; + vaxv) + basic_machine=vax-dec + os=-sysv + ;; + vms) + basic_machine=vax-dec + os=-vms + ;; + vpp*|vx|vx-*) + basic_machine=f301-fujitsu + ;; + vxworks960) + basic_machine=i960-wrs + os=-vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + os=-vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + os=-vxworks + ;; + w65*) + basic_machine=w65-wdc + os=-none + ;; + w89k-*) + basic_machine=hppa1.1-winbond + os=-proelf + ;; + xbox) + basic_machine=i686-pc + os=-mingw32 + ;; + xps | xps100) + basic_machine=xps100-honeywell + ;; + ymp) + basic_machine=ymp-cray + os=-unicos + ;; + z8k-*-coff) + basic_machine=z8k-unknown + os=-sim + ;; + none) + basic_machine=none-none + os=-none + ;; + +# Here we handle the default manufacturer of certain CPU types. It is in +# some cases the only manufacturer, in others, it is the most popular. + w89k) + basic_machine=hppa1.1-winbond + ;; + op50n) + basic_machine=hppa1.1-oki + ;; + op60c) + basic_machine=hppa1.1-oki + ;; + romp) + basic_machine=romp-ibm + ;; + mmix) + basic_machine=mmix-knuth + ;; + rs6000) + basic_machine=rs6000-ibm + ;; + vax) + basic_machine=vax-dec + ;; + pdp10) + # there are many clones, so DEC is not a safe bet + basic_machine=pdp10-unknown + ;; + pdp11) + basic_machine=pdp11-dec + ;; + we32k) + basic_machine=we32k-att + ;; + sh[1234] | sh[24]a | sh[34]eb | sh[1234]le | sh[23]ele) + basic_machine=sh-unknown + ;; + sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) + basic_machine=sparc-sun + ;; + cydra) + basic_machine=cydra-cydrome + ;; + orion) + basic_machine=orion-highlevel + ;; + orion105) + basic_machine=clipper-highlevel + ;; + mac | mpw | mac-mpw) + basic_machine=m68k-apple + ;; + pmac | pmac-mpw) + basic_machine=powerpc-apple + ;; + *-unknown) + # Make sure to match an already-canonicalized machine name. + ;; + *) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $basic_machine in + *-digital*) + basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` + ;; + *-commodore*) + basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if [ x"$os" != x"" ] +then +case $os in + # First match some system type aliases + # that might get confused with valid system types. + # -solaris* is a basic system type, with this one exception. + -solaris1 | -solaris1.*) + os=`echo $os | sed -e 's|solaris1|sunos4|'` + ;; + -solaris) + os=-solaris2 + ;; + -svr4*) + os=-sysv4 + ;; + -unixware*) + os=-sysv4.2uw + ;; + -gnu/linux*) + os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` + ;; + # First accept the basic system types. + # The portable systems comes first. + # Each alternative MUST END IN A *, to match a version number. + # -sysv* is not here because it comes later, after sysvr4. + -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ + | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ + | -aos* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ + | -openbsd* | -solidbsd* \ + | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ + | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ + | -chorusos* | -chorusrdb* \ + | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \ + | -uxpv* | -beos* | -mpeix* | -udk* \ + | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ + | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ + | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ + | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ + | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ + | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ + | -skyos* | -haiku* | -rdos* | -toppers* | -drops*) + # Remember, each alternative MUST END IN *, to match a version number. + ;; + -qnx*) + case $basic_machine in + x86-* | i*86-*) + ;; + *) + os=-nto$os + ;; + esac + ;; + -nto-qnx*) + ;; + -nto*) + os=`echo $os | sed -e 's|nto|nto-qnx|'` + ;; + -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ + | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ + | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) + ;; + -mac*) + os=`echo $os | sed -e 's|mac|macos|'` + ;; + -linux-dietlibc) + os=-linux-dietlibc + ;; + -linux*) + os=`echo $os | sed -e 's|linux|linux-gnu|'` + ;; + -sunos5*) + os=`echo $os | sed -e 's|sunos5|solaris2|'` + ;; + -sunos6*) + os=`echo $os | sed -e 's|sunos6|solaris3|'` + ;; + -opened*) + os=-openedition + ;; + -os400*) + os=-os400 + ;; + -wince*) + os=-wince + ;; + -osfrose*) + os=-osfrose + ;; + -osf*) + os=-osf + ;; + -utek*) + os=-bsd + ;; + -dynix*) + os=-bsd + ;; + -acis*) + os=-aos + ;; + -atheos*) + os=-atheos + ;; + -syllable*) + os=-syllable + ;; + -386bsd) + os=-bsd + ;; + -ctix* | -uts*) + os=-sysv + ;; + -nova*) + os=-rtmk-nova + ;; + -ns2 ) + os=-nextstep2 + ;; + -nsk*) + os=-nsk + ;; + # Preserve the version number of sinix5. + -sinix5.*) + os=`echo $os | sed -e 's|sinix|sysv|'` + ;; + -sinix*) + os=-sysv4 + ;; + -tpf*) + os=-tpf + ;; + -triton*) + os=-sysv3 + ;; + -oss*) + os=-sysv3 + ;; + -svr4) + os=-sysv4 + ;; + -svr3) + os=-sysv3 + ;; + -sysvr4) + os=-sysv4 + ;; + # This must come after -sysvr4. + -sysv*) + ;; + -ose*) + os=-ose + ;; + -es1800*) + os=-ose + ;; + -xenix) + os=-xenix + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + os=-mint + ;; + -aros*) + os=-aros + ;; + -kaos*) + os=-kaos + ;; + -zvmoe) + os=-zvmoe + ;; + -none) + ;; + *) + # Get rid of the `-' at the beginning of $os. + os=`echo $os | sed 's/[^-]*-//'` + echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 + exit 1 + ;; +esac +else + +# Here we handle the default operating systems that come with various machines. +# The value should be what the vendor currently ships out the door with their +# machine or put another way, the most popular os provided with the machine. + +# Note that if you're going to try to match "-MANUFACTURER" here (say, +# "-sun"), then you have to tell the case statement up towards the top +# that MANUFACTURER isn't an operating system. Otherwise, code above +# will signal an error saying that MANUFACTURER isn't an operating +# system, and we'll never get to this point. + +case $basic_machine in + score-*) + os=-elf + ;; + spu-*) + os=-elf + ;; + *-acorn) + os=-riscix1.2 + ;; + arm*-rebel) + os=-linux + ;; + arm*-semi) + os=-aout + ;; + c4x-* | tic4x-*) + os=-coff + ;; + # This must come before the *-dec entry. + pdp10-*) + os=-tops20 + ;; + pdp11-*) + os=-none + ;; + *-dec | vax-*) + os=-ultrix4.2 + ;; + m68*-apollo) + os=-domain + ;; + i386-sun) + os=-sunos4.0.2 + ;; + m68000-sun) + os=-sunos3 + # This also exists in the configure program, but was not the + # default. + # os=-sunos4 + ;; + m68*-cisco) + os=-aout + ;; + mep-*) + os=-elf + ;; + mips*-cisco) + os=-elf + ;; + mips*-*) + os=-elf + ;; + or32-*) + os=-coff + ;; + *-tti) # must be before sparc entry or we get the wrong os. + os=-sysv3 + ;; + sparc-* | *-sun) + os=-sunos4.1.1 + ;; + *-be) + os=-beos + ;; + *-haiku) + os=-haiku + ;; + *-ibm) + os=-aix + ;; + *-knuth) + os=-mmixware + ;; + *-wec) + os=-proelf + ;; + *-winbond) + os=-proelf + ;; + *-oki) + os=-proelf + ;; + *-hp) + os=-hpux + ;; + *-hitachi) + os=-hiux + ;; + i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) + os=-sysv + ;; + *-cbm) + os=-amigaos + ;; + *-dg) + os=-dgux + ;; + *-dolphin) + os=-sysv3 + ;; + m68k-ccur) + os=-rtu + ;; + m88k-omron*) + os=-luna + ;; + *-next ) + os=-nextstep + ;; + *-sequent) + os=-ptx + ;; + *-crds) + os=-unos + ;; + *-ns) + os=-genix + ;; + i370-*) + os=-mvs + ;; + *-next) + os=-nextstep3 + ;; + *-gould) + os=-sysv + ;; + *-highlevel) + os=-bsd + ;; + *-encore) + os=-bsd + ;; + *-sgi) + os=-irix + ;; + *-siemens) + os=-sysv4 + ;; + *-masscomp) + os=-rtu + ;; + f30[01]-fujitsu | f700-fujitsu) + os=-uxpv + ;; + *-rom68k) + os=-coff + ;; + *-*bug) + os=-coff + ;; + *-apple) + os=-macos + ;; + *-atari*) + os=-mint + ;; + *) + os=-none + ;; +esac +fi + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +vendor=unknown +case $basic_machine in + *-unknown) + case $os in + -riscix*) + vendor=acorn + ;; + -sunos*) + vendor=sun + ;; + -aix*) + vendor=ibm + ;; + -beos*) + vendor=be + ;; + -hpux*) + vendor=hp + ;; + -mpeix*) + vendor=hp + ;; + -hiux*) + vendor=hitachi + ;; + -unos*) + vendor=crds + ;; + -dgux*) + vendor=dg + ;; + -luna*) + vendor=omron + ;; + -genix*) + vendor=ns + ;; + -mvs* | -opened*) + vendor=ibm + ;; + -os400*) + vendor=ibm + ;; + -ptx*) + vendor=sequent + ;; + -tpf*) + vendor=ibm + ;; + -vxsim* | -vxworks* | -windiss*) + vendor=wrs + ;; + -aux*) + vendor=apple + ;; + -hms*) + vendor=hitachi + ;; + -mpw* | -macos*) + vendor=apple + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + vendor=atari + ;; + -vos*) + vendor=stratus + ;; + esac + basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` + ;; +esac + +echo $basic_machine$os +exit + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/configure b/configure new file mode 100755 index 0000000..508d09c --- a/dev/null +++ b/configure @@ -0,0 +1,25302 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.61 for ntfs-3g 2010.5.16. +# +# Report bugs to . +# +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, +# 2002, 2003, 2004, 2005, 2006 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=: + # Zsh 3.x and 4.x performs 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 + + + + +# PATH needs CR +# 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 + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi + +# Support unset when possible. +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +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.) +as_nl=' +' +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +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 + echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + { (exit 1); exit 1; } +fi + +# Work around bugs in pre-3.0 UWIN ksh. +for as_var in ENV MAIL MAILPATH +do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +for as_var in \ + LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ + LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ + LC_TELEPHONE LC_TIME +do + if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then + eval $as_var=C; export $as_var + else + ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var + fi +done + +# Required to use basename. +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 + + +# Name of the executable. +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# CDPATH. +$as_unset CDPATH + + +if test "x$CONFIG_SHELL" = x; then + if (eval ":") 2>/dev/null; then + as_have_required=yes +else + as_have_required=no +fi + + if test $as_have_required = yes && (eval ": +(as_func_return () { + (exit \$1) +} +as_func_success () { + as_func_return 0 +} +as_func_failure () { + as_func_return 1 +} +as_func_ret_success () { + return 0 +} +as_func_ret_failure () { + return 1 +} + +exitcode=0 +if as_func_success; then + : +else + exitcode=1 + echo as_func_success failed. +fi + +if as_func_failure; then + exitcode=1 + echo as_func_failure succeeded. +fi + +if as_func_ret_success; then + : +else + exitcode=1 + echo as_func_ret_success failed. +fi + +if as_func_ret_failure; then + exitcode=1 + echo as_func_ret_failure succeeded. +fi + +if ( set x; as_func_ret_success y && test x = \"\$1\" ); then + : +else + exitcode=1 + echo positional parameters were not saved. +fi + +test \$exitcode = 0) || { (exit 1); exit 1; } + +( + as_lineno_1=\$LINENO + as_lineno_2=\$LINENO + test \"x\$as_lineno_1\" != \"x\$as_lineno_2\" && + test \"x\`expr \$as_lineno_1 + 1\`\" = \"x\$as_lineno_2\") || { (exit 1); exit 1; } +") 2> /dev/null; then + : +else + as_candidate_shells= + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + case $as_dir in + /*) + for as_base in sh bash ksh sh5; do + as_candidate_shells="$as_candidate_shells $as_dir/$as_base" + done;; + esac +done +IFS=$as_save_IFS + + + for as_shell in $as_candidate_shells $SHELL; do + # Try only shells that exist, to save several forks. + if { test -f "$as_shell" || test -f "$as_shell.exe"; } && + { ("$as_shell") 2> /dev/null <<\_ASEOF +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs 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 + + +: +_ASEOF +}; then + CONFIG_SHELL=$as_shell + as_have_required=yes + if { "$as_shell" 2> /dev/null <<\_ASEOF +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs 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_func_return () { + (exit $1) +} +as_func_success () { + as_func_return 0 +} +as_func_failure () { + as_func_return 1 +} +as_func_ret_success () { + return 0 +} +as_func_ret_failure () { + return 1 +} + +exitcode=0 +if as_func_success; then + : +else + exitcode=1 + echo as_func_success failed. +fi + +if as_func_failure; then + exitcode=1 + echo as_func_failure succeeded. +fi + +if as_func_ret_success; then + : +else + exitcode=1 + echo as_func_ret_success failed. +fi + +if as_func_ret_failure; then + exitcode=1 + echo as_func_ret_failure succeeded. +fi + +if ( set x; as_func_ret_success y && test x = "$1" ); then + : +else + exitcode=1 + echo positional parameters were not saved. +fi + +test $exitcode = 0) || { (exit 1); exit 1; } + +( + as_lineno_1=$LINENO + as_lineno_2=$LINENO + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2") || { (exit 1); exit 1; } + +_ASEOF +}; then + break +fi + +fi + + done + + if test "x$CONFIG_SHELL" != x; then + for as_var in BASH_ENV ENV + do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var + done + export CONFIG_SHELL + exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"} +fi + + + if test $as_have_required = no; then + echo This script requires a shell more modern than all the + echo shells that I found on your system. Please install a + echo modern shell, or manually run the script under such a + echo shell if you do have one. + { (exit 1); exit 1; } +fi + + +fi + +fi + + + +(eval "as_func_return () { + (exit \$1) +} +as_func_success () { + as_func_return 0 +} +as_func_failure () { + as_func_return 1 +} +as_func_ret_success () { + return 0 +} +as_func_ret_failure () { + return 1 +} + +exitcode=0 +if as_func_success; then + : +else + exitcode=1 + echo as_func_success failed. +fi + +if as_func_failure; then + exitcode=1 + echo as_func_failure succeeded. +fi + +if as_func_ret_success; then + : +else + exitcode=1 + echo as_func_ret_success failed. +fi + +if as_func_ret_failure; then + exitcode=1 + echo as_func_ret_failure succeeded. +fi + +if ( set x; as_func_ret_success y && test x = \"\$1\" ); then + : +else + exitcode=1 + echo positional parameters were not saved. +fi + +test \$exitcode = 0") || { + echo No shell found that supports shell functions. + echo Please tell autoconf@gnu.org about your system, + echo including any error possibly output before this + echo message +} + + + + as_lineno_1=$LINENO + as_lineno_2=$LINENO + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || { + + # Create $as_me.lineno as a copy of $as_myself, but with $LINENO + # uniformly replaced by the line number. The first 'sed' inserts a + # line-number line after each line using $LINENO; the second 'sed' + # does the real work. The second script uses 'N' to pair each + # line-number line with the line containing $LINENO, and appends + # trailing '-' during substitution so that $LINENO is not a special + # case at line end. + # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the + # scripts with optimization help from Paolo Bonzini. 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" || + { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 + { (exit 1); exit 1; }; } + + # 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 +} + + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in +-n*) + case `echo 'x\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + *) ECHO_C='\c';; + esac;; +*) + ECHO_N='-n';; +esac + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +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 +fi +echo >conf$$.file +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 -p'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -p' +elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln +else + as_ln_s='cp -p' +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=: +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +if test -x / >/dev/null 2>&1; then + as_test_x='test -x' +else + if ls -dL / >/dev/null 2>&1; then + as_ls_L_option=L + else + as_ls_L_option= + fi + as_test_x=' + eval sh -c '\'' + if test -d "$1"; then + test -d "$1/."; + else + case $1 in + -*)set "./$1";; + esac; + case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in + ???[sx]*):;;*)false;;esac;fi + '\'' sh + ' +fi +as_executable_p=$as_test_x + +# 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'" + + + + +# Check that we are running under the correct shell. +SHELL=${CONFIG_SHELL-/bin/sh} + +case X$ECHO in +X*--fallback-echo) + # Remove one level of quotation (which was required for Make). + ECHO=`echo "$ECHO" | sed 's,\\\\\$\\$0,'$0','` + ;; +esac + +echo=${ECHO-echo} +if test "X$1" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift +elif test "X$1" = X--fallback-echo; then + # Avoid inline document here, it may be left over + : +elif test "X`($echo '\t') 2>/dev/null`" = 'X\t' ; then + # Yippee, $echo works! + : +else + # Restart under the correct shell. + exec $SHELL "$0" --no-reexec ${1+"$@"} +fi + +if test "X$1" = X--fallback-echo; then + # used as fallback echo + shift + cat </dev/null 2>&1 && unset CDPATH + +if test -z "$ECHO"; then +if test "X${echo_test_string+set}" != Xset; then +# find a string as large as possible, as long as the shell can cope with it + for cmd in 'sed 50q "$0"' 'sed 20q "$0"' 'sed 10q "$0"' 'sed 2q "$0"' 'echo test'; do + # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ... + if (echo_test_string=`eval $cmd`) 2>/dev/null && + echo_test_string=`eval $cmd` && + (test "X$echo_test_string" = "X$echo_test_string") 2>/dev/null + then + break + fi + done +fi + +if test "X`($echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + : +else + # The Solaris, AIX, and Digital Unix default echo programs unquote + # backslashes. This makes it impossible to quote backslashes using + # echo "$something" | sed 's/\\/\\\\/g' + # + # So, first we look for a working echo in the user's PATH. + + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for dir in $PATH /usr/ucb; do + IFS="$lt_save_ifs" + if (test -f $dir/echo || test -f $dir/echo$ac_exeext) && + test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + echo="$dir/echo" + break + fi + done + IFS="$lt_save_ifs" + + if test "X$echo" = Xecho; then + # We didn't find a better echo, so look for alternatives. + if test "X`(print -r '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`(print -r "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + # This shell has a builtin print -r that does the trick. + echo='print -r' + elif (test -f /bin/ksh || test -f /bin/ksh$ac_exeext) && + test "X$CONFIG_SHELL" != X/bin/ksh; then + # If we have ksh, try running configure again with it. + ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh} + export ORIGINAL_CONFIG_SHELL + CONFIG_SHELL=/bin/ksh + export CONFIG_SHELL + exec $CONFIG_SHELL "$0" --no-reexec ${1+"$@"} + else + # Try using printf. + echo='printf %s\n' + if test "X`($echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + # Cool, printf works + : + elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "$0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($ORIGINAL_CONFIG_SHELL "$0" --fallback-echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL + export CONFIG_SHELL + SHELL="$CONFIG_SHELL" + export SHELL + echo="$CONFIG_SHELL $0 --fallback-echo" + elif echo_testing_string=`($CONFIG_SHELL "$0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($CONFIG_SHELL "$0" --fallback-echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + echo="$CONFIG_SHELL $0 --fallback-echo" + else + # maybe with a smaller string... + prev=: + + for cmd in 'echo test' 'sed 2q "$0"' 'sed 10q "$0"' 'sed 20q "$0"' 'sed 50q "$0"'; do + if (test "X$echo_test_string" = "X`eval $cmd`") 2>/dev/null + then + break + fi + prev="$cmd" + done + + if test "$prev" != 'sed 50q "$0"'; then + echo_test_string=`eval $prev` + export echo_test_string + exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "$0" ${1+"$@"} + else + # Oops. We lost completely, so just stick with echo. + echo=echo + fi + fi + fi + fi +fi +fi + +# Copy echo and quote the copy suitably for passing to libtool from +# the Makefile, instead of quoting the original, which is used later. +ECHO=$echo +if test "X$ECHO" = "X$CONFIG_SHELL $0 --fallback-echo"; then + ECHO="$CONFIG_SHELL \\\$\$0 --fallback-echo" +fi + + + + +tagnames=${tagnames+${tagnames},}CXX + +tagnames=${tagnames+${tagnames},}F77 + +exec 7<&0 &1 + +# Name of the host. +# hostname on some systems (SVR3.2, 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= +SHELL=${CONFIG_SHELL-/bin/sh} + +# Identity of this package. +PACKAGE_NAME='ntfs-3g' +PACKAGE_TARNAME='ntfs-3g' +PACKAGE_VERSION='2010.5.16' +PACKAGE_STRING='ntfs-3g 2010.5.16' +PACKAGE_BUGREPORT='ntfs-3g-devel@lists.sf.net' + +ac_unique_file="src/ntfs-3g.c" +# 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='SHELL +PATH_SEPARATOR +PACKAGE_NAME +PACKAGE_TARNAME +PACKAGE_VERSION +PACKAGE_STRING +PACKAGE_BUGREPORT +exec_prefix +prefix +program_transform_name +bindir +sbindir +libexecdir +datarootdir +datadir +sysconfdir +sharedstatedir +localstatedir +includedir +oldincludedir +docdir +infodir +htmldir +dvidir +pdfdir +psdir +libdir +localedir +mandir +DEFS +ECHO_C +ECHO_N +ECHO_T +LIBS +build_alias +host_alias +target_alias +build +build_cpu +build_vendor +build_os +host +host_cpu +host_vendor +host_os +target +target_cpu +target_vendor +target_os +INSTALL_PROGRAM +INSTALL_SCRIPT +INSTALL_DATA +am__isrc +CYGPATH_W +PACKAGE +VERSION +ACLOCAL +AUTOCONF +AUTOMAKE +AUTOHEADER +MAKEINFO +install_sh +STRIP +INSTALL_STRIP_PROGRAM +mkdir_p +AWK +SET_MAKE +am__leading_dot +AMTAR +am__tar +am__untar +MAINTAINER_MODE_TRUE +MAINTAINER_MODE_FALSE +MAINT +CC +CFLAGS +LDFLAGS +CPPFLAGS +ac_ct_CC +EXEEXT +OBJEXT +DEPDIR +am__include +am__quote +AMDEP_TRUE +AMDEP_FALSE +AMDEPBACKSLASH +CCDEPMODE +am__fastdepCC_TRUE +am__fastdepCC_FALSE +LN_S +SED +GREP +EGREP +ECHO +AR +RANLIB +DSYMUTIL +NMEDIT +CPP +CXX +CXXFLAGS +ac_ct_CXX +CXXDEPMODE +am__fastdepCXX_TRUE +am__fastdepCXX_FALSE +CXXCPP +F77 +FFLAGS +ac_ct_F77 +LIBTOOL +MV +RM +LDCONFIG +PKG_CONFIG +FUSE_MODULE_CFLAGS +FUSE_MODULE_LIBS +LIBOBJS +pkgconfigdir +ntfs3gincludedir +rootbindir +rootsbindir +rootlibdir +LIBNTFS_3G_VERSION +LIBFUSE_LITE_LIBS +OUTPUT_FORMAT +FUSE_INTERNAL_TRUE +FUSE_INTERNAL_FALSE +GENERATE_LDSCRIPT_TRUE +GENERATE_LDSCRIPT_FALSE +WINDOWS_TRUE +WINDOWS_FALSE +NTFS_DEVICE_DEFAULT_IO_OPS_TRUE +NTFS_DEVICE_DEFAULT_IO_OPS_FALSE +RUN_LDCONFIG_TRUE +RUN_LDCONFIG_FALSE +REALLYSTATIC_TRUE +REALLYSTATIC_FALSE +INSTALL_LIBRARY_TRUE +INSTALL_LIBRARY_FALSE +ENABLE_MOUNT_HELPER_TRUE +ENABLE_MOUNT_HELPER_FALSE +MKDIR_P +LTLIBOBJS' +ac_subst_files='' + ac_precious_vars='build_alias +host_alias +target_alias +CC +CFLAGS +LDFLAGS +LIBS +CPPFLAGS +CPP +CXX +CXXFLAGS +CCC +CXXCPP +F77 +FFLAGS +LDCONFIG +PKG_CONFIG +FUSE_MODULE_CFLAGS +FUSE_MODULE_LIBS' + + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +# 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' +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=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_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_feature" : ".*[^-._$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid feature name: $ac_feature" >&2 + { (exit 1); exit 1; }; } + ac_feature=`echo $ac_feature | sed 's/[-.]/_/g'` + eval enable_$ac_feature=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_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_feature" : ".*[^-._$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid feature name: $ac_feature" >&2 + { (exit 1); exit 1; }; } + ac_feature=`echo $ac_feature | sed 's/[-.]/_/g'` + eval enable_$ac_feature=\$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 ;; + + -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_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_package" : ".*[^-._$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid package name: $ac_package" >&2 + { (exit 1); exit 1; }; } + ac_package=`echo $ac_package | sed 's/[-.]/_/g'` + eval with_$ac_package=\$ac_optarg ;; + + -without-* | --without-*) + ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_package" : ".*[^-._$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid package name: $ac_package" >&2 + { (exit 1); exit 1; }; } + ac_package=`echo $ac_package | sed 's/[-.]/_/g'` + eval with_$ac_package=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 ;; + + -*) { echo "$as_me: error: unrecognized option: $ac_option +Try \`$0 --help' for more information." >&2 + { (exit 1); exit 1; }; } + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid variable name: $ac_envvar" >&2 + { (exit 1); exit 1; }; } + eval $ac_envvar=\$ac_optarg + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + 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'` + { echo "$as_me: error: missing argument to $ac_option" >&2 + { (exit 1); exit 1; }; } +fi + +# Be sure to have absolute directory names. +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 +do + eval ac_val=\$$ac_var + case $ac_val in + [\\/$]* | ?:[\\/]* ) continue;; + NONE | '' ) case $ac_var in *prefix ) continue;; esac;; + esac + { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 + { (exit 1); exit 1; }; } +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 + echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. + If a cross compiler is detected then cross compile mode will be used." >&2 + 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 .` || + { echo "$as_me: error: Working directory cannot be determined" >&2 + { (exit 1); exit 1; }; } +test "X$ac_ls_di" = "X$ac_pwd_ls_di" || + { echo "$as_me: error: pwd does not report name of working directory" >&2 + { (exit 1); exit 1; }; } + + +# 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 -- "$0" || +$as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$0" : 'X\(//\)[^/]' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +echo X"$0" | + 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 .." + { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2 + { (exit 1); exit 1; }; } +fi +ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" +ac_abs_confdir=`( + cd "$srcdir" && test -r "./$ac_unique_file" || { echo "$as_me: error: $ac_msg" >&2 + { (exit 1); exit 1; }; } + 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 ntfs-3g 2010.5.16 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] + --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/ntfs-3g] + --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 + +System types: + --build=BUILD configure for building on BUILD [guessed] + --host=HOST cross-compile to build programs to run on HOST [BUILD] + --target=TARGET configure for building compilers for TARGET [HOST] +_ACEOF +fi + +if test -n "$ac_init_help"; then + case $ac_init_help in + short | recursive ) echo "Configuration of ntfs-3g 2010.5.16:";; + esac + cat <<\_ACEOF + +Optional Features: + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --enable-maintainer-mode enable make rules and dependencies not useful + (and sometimes confusing) to the casual installer + --enable-debug enable debugging code and output + --enable-warnings enable lots of compiler warnings + --enable-pedantic enable compile pedantic mode + --enable-really-static create fully static binaries + --enable-mount-helper install mount helper [default=enabled for linux] + --enable-ldscript use ldscript instead of .so symlink + --disable-ldconfig do not update dynamic linker cache using ldconfig + --disable-library do not install libntfs-3g but link it into ntfs-3g + --disable-mtab disable and ignore usage of /etc/mtab + --enable-posix-acls enable POSIX ACL support + --disable-device-default-io-ops + install default IO ops + --disable-nfconv disable the 'nfconv' patch, which adds support for + Unicode normalization form conversion when built on + Mac OS X [default=enabled for Mac OS X] + --disable-dependency-tracking speeds up one-time build + --enable-dependency-tracking do not reject slow dependency extractors + --enable-shared[=PKGS] build shared libraries [default=yes] + --enable-static[=PKGS] build static libraries [default=yes] + --enable-fast-install[=PKGS] + optimize for fast installation [default=yes] + --disable-libtool-lock avoid locking (might break parallel builds) + --disable-largefile omit support for large files + +Optional Packages: + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --with-gnu-ld assume the C compiler uses GNU ld [default=no] + --with-pic try to use only PIC/non-PIC objects [default=use + both] + --with-tags[=TAGS] include additional configurations [automatic] + --with-fuse= + Select FUSE library: internal or external + [default=internal] + +Some influential environment variables: + CC C compiler command + CFLAGS 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 C/C++/Objective C preprocessor flags, e.g. -I if + you have headers in a nonstandard directory + CPP C preprocessor + CXX C++ compiler command + CXXFLAGS C++ compiler flags + CXXCPP C++ preprocessor + F77 Fortran 77 compiler command + FFLAGS Fortran 77 compiler flags + LDCONFIG ldconfig utility + PKG_CONFIG path to pkg-config utility + FUSE_MODULE_CFLAGS + C compiler flags for FUSE_MODULE, overriding pkg-config + FUSE_MODULE_LIBS + linker flags for FUSE_MODULE, overriding pkg-config + +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" || continue + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`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 + 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 +ntfs-3g configure 2010.5.16 +generated by GNU Autoconf 2.61 + +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, +2002, 2003, 2004, 2005, 2006 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 +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 ntfs-3g $as_me 2010.5.16, which was +generated by GNU Autoconf 2.61. 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=. + 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=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;; + 2) + ac_configure_args1="$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 + ac_configure_args="$ac_configure_args '$ac_arg'" + ;; + esac + done +done +$as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; } +$as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export 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 + + cat <<\_ASBOX +## ---------------- ## +## Cache variables. ## +## ---------------- ## +_ASBOX + 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_*) { echo "$as_me:$LINENO: WARNING: Cache variable $ac_var contains a newline." >&5 +echo "$as_me: WARNING: Cache variable $ac_var contains a newline." >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + *) $as_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 + + cat <<\_ASBOX +## ----------------- ## +## Output variables. ## +## ----------------- ## +_ASBOX + echo + for ac_var in $ac_subst_vars + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + echo "$ac_var='\''$ac_val'\''" + done | sort + echo + + if test -n "$ac_subst_files"; then + cat <<\_ASBOX +## ------------------- ## +## File substitutions. ## +## ------------------- ## +_ASBOX + echo + for ac_var in $ac_subst_files + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + echo "$ac_var='\''$ac_val'\''" + done | sort + echo + fi + + if test -s confdefs.h; then + cat <<\_ASBOX +## ----------- ## +## confdefs.h. ## +## ----------- ## +_ASBOX + echo + cat confdefs.h + echo + fi + test "$ac_signal" != 0 && + echo "$as_me: caught signal $ac_signal" + 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'; { (exit 1); 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 + +# 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 + + +# Let the site file select an alternate cache file if it wants to. +# Prefer explicitly selected file to automatically selected ones. +if test -n "$CONFIG_SITE"; then + set x "$CONFIG_SITE" +elif test "x$prefix" != xNONE; then + set x "$prefix/share/config.site" "$prefix/etc/config.site" +else + set x "$ac_default_prefix/share/config.site" \ + "$ac_default_prefix/etc/config.site" +fi +shift +for ac_site_file +do + if test -r "$ac_site_file"; then + { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5 +echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" + 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. + if test -f "$cache_file"; then + { echo "$as_me:$LINENO: loading cache $cache_file" >&5 +echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . "$cache_file";; + *) . "./$cache_file";; + esac + fi +else + { echo "$as_me:$LINENO: creating cache $cache_file" >&5 +echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +ac_header_list="$ac_header_list utime.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,) + { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5 +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 + { echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5 +echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + { echo "$as_me:$LINENO: former value: $ac_old_val" >&5 +echo "$as_me: former value: $ac_old_val" >&2;} + { echo "$as_me:$LINENO: current value: $ac_new_val" >&5 +echo "$as_me: current value: $ac_new_val" >&2;} + ac_cache_corrupted=: + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *\'*) ac_arg=$ac_var=`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. + *) ac_configure_args="$ac_configure_args '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5 +echo "$as_me: error: changes in the environment can compromise the build" >&2;} + { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5 +echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;} + { (exit 1); exit 1; }; } +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 + + +LIBNTFS_3G_VERSION="76" + + +# Environment +ac_aux_dir= +for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; 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 + { { echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" >&5 +echo "$as_me: error: cannot find install-sh or install.sh in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" >&2;} + { (exit 1); exit 1; }; } +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. + + +# Make sure we can run config.sub. +$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || + { { echo "$as_me:$LINENO: error: cannot run $SHELL $ac_aux_dir/config.sub" >&5 +echo "$as_me: error: cannot run $SHELL $ac_aux_dir/config.sub" >&2;} + { (exit 1); exit 1; }; } + +{ echo "$as_me:$LINENO: checking build system type" >&5 +echo $ECHO_N "checking build system type... $ECHO_C" >&6; } +if test "${ac_cv_build+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_build_alias=$build_alias +test "x$ac_build_alias" = x && + ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` +test "x$ac_build_alias" = x && + { { echo "$as_me:$LINENO: error: cannot guess build type; you must specify one" >&5 +echo "$as_me: error: cannot guess build type; you must specify one" >&2;} + { (exit 1); exit 1; }; } +ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || + { { echo "$as_me:$LINENO: error: $SHELL $ac_aux_dir/config.sub $ac_build_alias failed" >&5 +echo "$as_me: error: $SHELL $ac_aux_dir/config.sub $ac_build_alias failed" >&2;} + { (exit 1); exit 1; }; } + +fi +{ echo "$as_me:$LINENO: result: $ac_cv_build" >&5 +echo "${ECHO_T}$ac_cv_build" >&6; } +case $ac_cv_build in +*-*-*) ;; +*) { { echo "$as_me:$LINENO: error: invalid value of canonical build" >&5 +echo "$as_me: error: invalid value of canonical build" >&2;} + { (exit 1); exit 1; }; };; +esac +build=$ac_cv_build +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_build +shift +build_cpu=$1 +build_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +build_os=$* +IFS=$ac_save_IFS +case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac + + +{ echo "$as_me:$LINENO: checking host system type" >&5 +echo $ECHO_N "checking host system type... $ECHO_C" >&6; } +if test "${ac_cv_host+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test "x$host_alias" = x; then + ac_cv_host=$ac_cv_build +else + ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || + { { echo "$as_me:$LINENO: error: $SHELL $ac_aux_dir/config.sub $host_alias failed" >&5 +echo "$as_me: error: $SHELL $ac_aux_dir/config.sub $host_alias failed" >&2;} + { (exit 1); exit 1; }; } +fi + +fi +{ echo "$as_me:$LINENO: result: $ac_cv_host" >&5 +echo "${ECHO_T}$ac_cv_host" >&6; } +case $ac_cv_host in +*-*-*) ;; +*) { { echo "$as_me:$LINENO: error: invalid value of canonical host" >&5 +echo "$as_me: error: invalid value of canonical host" >&2;} + { (exit 1); exit 1; }; };; +esac +host=$ac_cv_host +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_host +shift +host_cpu=$1 +host_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +host_os=$* +IFS=$ac_save_IFS +case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac + + +{ echo "$as_me:$LINENO: checking target system type" >&5 +echo $ECHO_N "checking target system type... $ECHO_C" >&6; } +if test "${ac_cv_target+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test "x$target_alias" = x; then + ac_cv_target=$ac_cv_host +else + ac_cv_target=`$SHELL "$ac_aux_dir/config.sub" $target_alias` || + { { echo "$as_me:$LINENO: error: $SHELL $ac_aux_dir/config.sub $target_alias failed" >&5 +echo "$as_me: error: $SHELL $ac_aux_dir/config.sub $target_alias failed" >&2;} + { (exit 1); exit 1; }; } +fi + +fi +{ echo "$as_me:$LINENO: result: $ac_cv_target" >&5 +echo "${ECHO_T}$ac_cv_target" >&6; } +case $ac_cv_target in +*-*-*) ;; +*) { { echo "$as_me:$LINENO: error: invalid value of canonical target" >&5 +echo "$as_me: error: invalid value of canonical target" >&2;} + { (exit 1); exit 1; }; };; +esac +target=$ac_cv_target +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_target +shift +target_cpu=$1 +target_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +target_os=$* +IFS=$ac_save_IFS +case $target_os in *\ *) target_os=`echo "$target_os" | sed 's/ /-/g'`;; esac + + +# The aliases save the names the user supplied, while $host etc. +# will get canonicalized. +test -n "$target_alias" && + test "$program_prefix$program_suffix$program_transform_name" = \ + NONENONEs,x,x, && + program_prefix=${target_alias}- + +# Automake +am__api_version='1.10' + +# 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. +{ echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5 +echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6; } +if test -z "$INSTALL"; then +if test "${ac_cv_path_install+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&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 { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$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 + ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" + break 3 + fi + fi + done + done + ;; +esac +done +IFS=$as_save_IFS + + +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 +{ echo "$as_me:$LINENO: result: $INSTALL" >&5 +echo "${ECHO_T}$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' + +{ echo "$as_me:$LINENO: checking whether build environment is sane" >&5 +echo $ECHO_N "checking whether build environment is sane... $ECHO_C" >&6; } +# Just in case +sleep 1 +echo timestamp > conftest.file +# 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 ( + 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 + rm -f conftest.file + 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". + { { echo "$as_me:$LINENO: error: ls -t appears to fail. Make sure there is not a broken +alias in your environment" >&5 +echo "$as_me: error: ls -t appears to fail. Make sure there is not a broken +alias in your environment" >&2;} + { (exit 1); exit 1; }; } + fi + + test "$2" = conftest.file + ) +then + # Ok. + : +else + { { echo "$as_me:$LINENO: error: newly created file is older than distributed files! +Check your system clock" >&5 +echo "$as_me: error: newly created file is older than distributed files! +Check your system clock" >&2;} + { (exit 1); exit 1; }; } +fi +{ echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } +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 $. echo might interpret backslashes. +# By default was `s,x,x', remove it if useless. +cat <<\_ACEOF >conftest.sed +s/[\\$]/&&/g;s/;s,x,x,$// +_ACEOF +program_transform_name=`echo $program_transform_name | sed -f conftest.sed` +rm -f conftest.sed + +# expand $ac_aux_dir to an absolute path +am_aux_dir=`cd $ac_aux_dir && pwd` + +test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing" +# Use eval to expand $SHELL +if eval "$MISSING --run true"; then + am_missing_run="$MISSING --run " +else + am_missing_run= + { echo "$as_me:$LINENO: WARNING: \`missing' script is too old or missing" >&5 +echo "$as_me: WARNING: \`missing' script is too old or missing" >&2;} +fi + +{ echo "$as_me:$LINENO: checking for a thread-safe mkdir -p" >&5 +echo $ECHO_N "checking for a thread-safe mkdir -p... $ECHO_C" >&6; } +if test -z "$MKDIR_P"; then + if test "${ac_cv_path_mkdir+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&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 + { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$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 + + 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. + test -d ./--version && rmdir ./--version + MKDIR_P="$ac_install_sh -d" + fi +fi +{ echo "$as_me:$LINENO: result: $MKDIR_P" >&5 +echo "${ECHO_T}$MKDIR_P" >&6; } + +mkdir_p="$MKDIR_P" +case $mkdir_p in + [\\/$]* | ?:[\\/]*) ;; + */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;; +esac + +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 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_AWK+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&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 { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_AWK="$ac_prog" + echo "$as_me:$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 + { echo "$as_me:$LINENO: result: $AWK" >&5 +echo "${ECHO_T}$AWK" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + + test -n "$AWK" && break +done + +{ echo "$as_me:$LINENO: checking whether ${MAKE-make} sets \$(MAKE)" >&5 +echo $ECHO_N "checking whether ${MAKE-make} sets \$(MAKE)... $ECHO_C" >&6; } +set x ${MAKE-make}; ac_make=`echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` +if { as_var=ac_cv_prog_make_${ac_make}_set; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&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 + { echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } + SET_MAKE= +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}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 + +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 + { { echo "$as_me:$LINENO: error: source directory already configured; run \"make distclean\" there first" >&5 +echo "$as_me: error: source directory already configured; run \"make distclean\" there first" >&2;} + { (exit 1); exit 1; }; } + 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=${PACKAGE_NAME} + VERSION=${PACKAGE_VERSION} + + +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"} + +install_sh=${install_sh-"\$(SHELL) $am_aux_dir/install-sh"} + +# 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 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_STRIP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&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 { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_STRIP="${ac_tool_prefix}strip" + echo "$as_me:$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 + { echo "$as_me:$LINENO: result: $STRIP" >&5 +echo "${ECHO_T}$STRIP" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}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 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&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 { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_STRIP="strip" + echo "$as_me:$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 + { echo "$as_me:$LINENO: result: $ac_ct_STRIP" >&5 +echo "${ECHO_T}$ac_ct_STRIP" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + if test "x$ac_ct_STRIP" = x; then + STRIP=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&5 +echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&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" + +# We need awk for the "check" target. The system "awk" is bad on +# some platforms. +# Always define AMTAR for backward compatibility. + +AMTAR=${AMTAR-"${am_missing_run}tar"} + +am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -' + + + + + +ac_config_headers="$ac_config_headers config.h" + + +{ echo "$as_me:$LINENO: checking whether to enable maintainer-specific portions of Makefiles" >&5 +echo $ECHO_N "checking whether to enable maintainer-specific portions of Makefiles... $ECHO_C" >&6; } + # Check whether --enable-maintainer-mode was given. +if test "${enable_maintainer_mode+set}" = set; then + enableval=$enable_maintainer_mode; USE_MAINTAINER_MODE=$enableval +else + USE_MAINTAINER_MODE=no +fi + + { echo "$as_me:$LINENO: result: $USE_MAINTAINER_MODE" >&5 +echo "${ECHO_T}$USE_MAINTAINER_MODE" >&6; } + if test $USE_MAINTAINER_MODE = yes; then + MAINTAINER_MODE_TRUE= + MAINTAINER_MODE_FALSE='#' +else + MAINTAINER_MODE_TRUE='#' + MAINTAINER_MODE_FALSE= +fi + + MAINT=$MAINTAINER_MODE_TRUE + + + +# Options +# Check whether --enable-debug was given. +if test "${enable_debug+set}" = set; then + enableval=$enable_debug; +else + enable_debug="no" + +fi + + +# Check whether --enable-warnings was given. +if test "${enable_warnings+set}" = set; then + enableval=$enable_warnings; +else + enable_warnings="no" + +fi + + +# Check whether --enable-pedantic was given. +if test "${enable_pedantic+set}" = set; then + enableval=$enable_pedantic; +else + enable_pedantic="no" + +fi + + +# Check whether --enable-really-static was given. +if test "${enable_really_static+set}" = set; then + enableval=$enable_really_static; +else + enable_really_static="no" + +fi + + +# Check whether --enable-mount-helper was given. +if test "${enable_mount_helper+set}" = set; then + enableval=$enable_mount_helper; +else + + case "${target_os}" in + linux*) enable_mount_helper="yes" ;; + *) enable_mount_helper="no" ;; + esac + + +fi + + +# Check whether --enable-ldscript was given. +if test "${enable_ldscript+set}" = set; then + enableval=$enable_ldscript; +else + enable_ldscript="no" + +fi + + +# Check whether --enable-ldconfig was given. +if test "${enable_ldconfig+set}" = set; then + enableval=$enable_ldconfig; +else + enable_ldconfig="yes" + +fi + + +# Check whether --enable-library was given. +if test "${enable_library+set}" = set; then + enableval=$enable_library; +else + enable_library="yes" + +fi + + +# Check whether --enable-mtab was given. +if test "${enable_mtab+set}" = set; then + enableval=$enable_mtab; +else + enable_mtab="yes" + +fi + + +# Check whether --enable-posix-acls was given. +if test "${enable_posix_acls+set}" = set; then + enableval=$enable_posix_acls; +else + enable_posix_acls="no" + +fi + + +# Check whether --enable-device-default-io-ops was given. +if test "${enable_device_default_io_ops+set}" = set; then + enableval=$enable_device_default_io_ops; +else + enable_device_default_io_ops="yes" + +fi + + +# Check whether --enable-nfconv was given. +if test "${enable_nfconv+set}" = set; then + enableval=$enable_nfconv; enable_nfconv="no" +else + + case "${target_os}" in + darwin*) enable_nfconv="yes" ;; + *) enable_nfconv="no" ;; + esac + + +fi + + +# pthread_rwlock_t requires _GNU_SOURCE + +cat >>confdefs.h <<\_ACEOF +#define _GNU_SOURCE 1 +_ACEOF + + + +# Programs +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 +if test -n "$ac_tool_prefix"; then + for ac_prog in gcc cc + 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 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # 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 { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in gcc cc +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # 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 { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CC="$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + + test -n "$ac_ct_CC" && break +done + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&5 +echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +fi + + +test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH +See \`config.log' for more details." >&5 +echo "$as_me: error: no acceptable C compiler found in \$PATH +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } + +# Provide some information about the compiler. +echo "$as_me:$LINENO: checking for C compiler version" >&5 +ac_compiler=`set X $ac_compile; echo $2` +{ (ac_try="$ac_compiler --version >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compiler --version >&5") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (ac_try="$ac_compiler -v >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compiler -v >&5") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (ac_try="$ac_compiler -V >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compiler -V >&5") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out 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. +{ echo "$as_me:$LINENO: checking for C compiler default output file name" >&5 +echo $ECHO_N "checking for C compiler default output file name... $ECHO_C" >&6; } +ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` +# +# List of possible output files, starting from the most likely. +# The algorithm is not robust to junk in `.', hence go to wildcards (a.*) +# only as a last resort. b.out is created by i960 compilers. +ac_files='a_out.exe a.exe conftest.exe a.out conftest a.* conftest.* b.out' +# +# The IRIX 6 linker writes into existing files which may not be +# executable, retaining their permissions. Remove them first so a +# subsequent execution test works. +ac_rmfiles= +for ac_file in $ac_files +do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link_default") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; 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 | *.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 + +{ echo "$as_me:$LINENO: result: $ac_file" >&5 +echo "${ECHO_T}$ac_file" >&6; } +if test -z "$ac_file"; then + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { echo "$as_me:$LINENO: error: C compiler cannot create executables +See \`config.log' for more details." >&5 +echo "$as_me: error: C compiler cannot create executables +See \`config.log' for more details." >&2;} + { (exit 77); exit 77; }; } +fi + +ac_exeext=$ac_cv_exeext + +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ echo "$as_me:$LINENO: checking whether the C compiler works" >&5 +echo $ECHO_N "checking whether the C compiler works... $ECHO_C" >&6; } +# FIXME: These cross compiler hacks should be removed for Autoconf 3.0 +# If not cross compiling, check that we can run a simple program. +if test "$cross_compiling" != yes; then + if { ac_try='./$ac_file' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { echo "$as_me:$LINENO: error: cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } + fi + fi +fi +{ echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } + +rm -f a.out a.exe conftest$ac_cv_exeext b.out +ac_clean_files=$ac_clean_files_save +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ echo "$as_me:$LINENO: checking whether we are cross compiling" >&5 +echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6; } +{ echo "$as_me:$LINENO: result: $cross_compiling" >&5 +echo "${ECHO_T}$cross_compiling" >&6; } + +{ echo "$as_me:$LINENO: checking for suffix of executables" >&5 +echo $ECHO_N "checking for suffix of executables... $ECHO_C" >&6; } +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; 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 | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + break;; + * ) break;; + esac +done +else + { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +rm -f conftest$ac_cv_exeext +{ echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5 +echo "${ECHO_T}$ac_cv_exeext" >&6; } + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +{ echo "$as_me:$LINENO: checking for suffix of object files" >&5 +echo $ECHO_N "checking for suffix of object files... $ECHO_C" >&6; } +if test "${ac_cv_objext+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* 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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; 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 ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute suffix of object files: cannot compile +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ac_cv_objext" >&5 +echo "${ECHO_T}$ac_cv_objext" >&6; } +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +{ echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5 +echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6; } +if test "${ac_cv_c_compiler_gnu+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_compiler_gnu=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_compiler_gnu=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +{ echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5 +echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6; } +GCC=`test $ac_compiler_gnu = yes && echo yes` +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +{ echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5 +echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6; } +if test "${ac_cv_prog_cc_g+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_save_c_werror_flag=$ac_c_werror_flag + ac_c_werror_flag=yes + ac_cv_prog_cc_g=no + CFLAGS="-g" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_prog_cc_g=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + CFLAGS="" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_c_werror_flag=$ac_save_c_werror_flag + CFLAGS="-g" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_prog_cc_g=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +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_c_werror_flag=$ac_save_c_werror_flag +fi +{ echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5 +echo "${ECHO_T}$ac_cv_prog_cc_g" >&6; } +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +{ echo "$as_me:$LINENO: checking for $CC option to accept ISO C89" >&5 +echo $ECHO_N "checking for $CC option to accept ISO C89... $ECHO_C" >&6; } +if test "${ac_cv_prog_cc_c89+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_prog_cc_c89=no +ac_save_CC=$CC +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#include +#include +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters + inside strings and character constants. */ +#define FOO(x) 'x' +int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ + -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + 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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_prog_cc_c89=$ac_arg +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext + test "x$ac_cv_prog_cc_c89" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC + +fi +# AC_CACHE_VAL +case "x$ac_cv_prog_cc_c89" in + x) + { echo "$as_me:$LINENO: result: none needed" >&5 +echo "${ECHO_T}none needed" >&6; } ;; + xno) + { echo "$as_me:$LINENO: result: unsupported" >&5 +echo "${ECHO_T}unsupported" >&6; } ;; + *) + CC="$CC $ac_cv_prog_cc_c89" + { echo "$as_me:$LINENO: result: $ac_cv_prog_cc_c89" >&5 +echo "${ECHO_T}$ac_cv_prog_cc_c89" >&6; } ;; +esac + + +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" + + +am_make=${MAKE-make} +cat > confinc << 'END' +am__doit: + @echo done +.PHONY: am__doit +END +# If we don't find an include directive, just comment out the code. +{ echo "$as_me:$LINENO: checking for style of include used by $am_make" >&5 +echo $ECHO_N "checking for style of include used by $am_make... $ECHO_C" >&6; } +am__include="#" +am__quote= +_am_result=none +# First try GNU make style include. +echo "include confinc" > confmf +# We grep out `Entering directory' and `Leaving directory' +# messages which can occur if `w' ends up in MAKEFLAGS. +# In particular we don't look at `^make:' because GNU make might +# be invoked under some other name (usually "gmake"), in which +# case it prints its new name instead of `make'. +if test "`$am_make -s -f confmf 2> /dev/null | grep -v 'ing directory'`" = "done"; then + am__include=include + am__quote= + _am_result=GNU +fi +# Now try BSD make style include. +if test "$am__include" = "#"; then + echo '.include "confinc"' > confmf + if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then + am__include=.include + am__quote="\"" + _am_result=BSD + fi +fi + + +{ echo "$as_me:$LINENO: result: $_am_result" >&5 +echo "${ECHO_T}$_am_result" >&6; } +rm -f confinc confmf + +# 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='\' +fi + if test "x$enable_dependency_tracking" != xno; then + AMDEP_TRUE= + AMDEP_FALSE='#' +else + AMDEP_TRUE='#' + AMDEP_FALSE= +fi + + + +depcc="$CC" am_compiler_list= + +{ echo "$as_me:$LINENO: checking dependency style of $depcc" >&5 +echo $ECHO_N "checking dependency style of $depcc... $ECHO_C" >&6; } +if test "${am_cv_CC_dependencies_compiler_type+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&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'. + 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_CC_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` + fi + 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 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + case $depmode in + 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 + ;; + none) break ;; + esac + # 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. + if depmode=$depmode \ + source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} 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 sub/conftest.${OBJEXT-o} 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_CC_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_CC_dependencies_compiler_type=none +fi + +fi +{ echo "$as_me:$LINENO: result: $am_cv_CC_dependencies_compiler_type" >&5 +echo "${ECHO_T}$am_cv_CC_dependencies_compiler_type" >&6; } +CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type + + if + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then + am__fastdepCC_TRUE= + am__fastdepCC_FALSE='#' +else + am__fastdepCC_TRUE='#' + am__fastdepCC_FALSE= +fi + + +{ echo "$as_me:$LINENO: checking whether ln -s works" >&5 +echo $ECHO_N "checking whether ln -s works... $ECHO_C" >&6; } +LN_S=$as_ln_s +if test "$LN_S" = "ln -s"; then + { echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } +else + { echo "$as_me:$LINENO: result: no, using $LN_S" >&5 +echo "${ECHO_T}no, using $LN_S" >&6; } +fi + +if test "x$CC" != xcc; then + { echo "$as_me:$LINENO: checking whether $CC and cc understand -c and -o together" >&5 +echo $ECHO_N "checking whether $CC and cc understand -c and -o together... $ECHO_C" >&6; } +else + { echo "$as_me:$LINENO: checking whether cc understands -c and -o together" >&5 +echo $ECHO_N "checking whether cc understands -c and -o together... $ECHO_C" >&6; } +fi +set dummy $CC; ac_cc=`echo $2 | + sed 's/[^a-zA-Z0-9_]/_/g;s/^[0-9]/_/'` +if { as_var=ac_cv_prog_cc_${ac_cc}_c_o; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +# Make sure it works both with $CC and with simple cc. +# We do the test twice because some compilers refuse to overwrite an +# existing .o file with -o, though they will create one. +ac_try='$CC -c conftest.$ac_ext -o conftest2.$ac_objext >&5' +rm -f conftest2.* +if { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + test -f conftest2.$ac_objext && { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; +then + eval ac_cv_prog_cc_${ac_cc}_c_o=yes + if test "x$CC" != xcc; then + # Test first that cc exists at all. + if { ac_try='cc -c conftest.$ac_ext >&5' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_try='cc -c conftest.$ac_ext -o conftest2.$ac_objext >&5' + rm -f conftest2.* + if { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + test -f conftest2.$ac_objext && { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; + then + # cc works too. + : + else + # cc exists but doesn't like -o. + eval ac_cv_prog_cc_${ac_cc}_c_o=no + fi + fi + fi +else + eval ac_cv_prog_cc_${ac_cc}_c_o=no +fi +rm -f core conftest* + +fi +if eval test \$ac_cv_prog_cc_${ac_cc}_c_o = yes; then + { echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } + +cat >>confdefs.h <<\_ACEOF +#define NO_MINUS_C_MINUS_O 1 +_ACEOF + +fi + +# FIXME: we rely on the cache variable name because +# there is no other way. +set dummy $CC +ac_cc=`echo $2 | sed 's/[^a-zA-Z0-9_]/_/g;s/^[0-9]/_/'` +if eval "test \"`echo '$ac_cv_prog_cc_'${ac_cc}_c_o`\" != yes"; then + # Losing compiler, so override with the script. + # FIXME: It is wrong to rewrite CC. + # But if we don't then we get into trouble of one sort or another. + # A longer-term fix would be to have automake use am__CC in this case, + # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" + CC="$am_aux_dir/compile $CC" +fi + + + +# Check whether --enable-shared was given. +if test "${enable_shared+set}" = set; then + enableval=$enable_shared; p=${PACKAGE-default} + case $enableval in + yes) enable_shared=yes ;; + no) enable_shared=no ;; + *) + enable_shared=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_shared=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac +else + enable_shared=yes +fi + + +# Check whether --enable-static was given. +if test "${enable_static+set}" = set; then + enableval=$enable_static; p=${PACKAGE-default} + case $enableval in + yes) enable_static=yes ;; + no) enable_static=no ;; + *) + enable_static=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_static=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac +else + enable_static=yes +fi + + +# Check whether --enable-fast-install was given. +if test "${enable_fast_install+set}" = set; then + enableval=$enable_fast_install; p=${PACKAGE-default} + case $enableval in + yes) enable_fast_install=yes ;; + no) enable_fast_install=no ;; + *) + enable_fast_install=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_fast_install=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac +else + enable_fast_install=yes +fi + + +{ echo "$as_me:$LINENO: checking for a sed that does not truncate output" >&5 +echo $ECHO_N "checking for a sed that does not truncate output... $ECHO_C" >&6; } +if test "${lt_cv_path_SED+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # Loop through the user's path and test for sed and gsed. +# Then use that list of sed's as ones to test for truncation. +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for lt_ac_prog in sed gsed; do + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$lt_ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$lt_ac_prog$ac_exec_ext"; }; then + lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext" + fi + done + done +done +IFS=$as_save_IFS +lt_ac_max=0 +lt_ac_count=0 +# Add /usr/xpg4/bin/sed as it is typically found on Solaris +# along with /bin/sed that truncates output. +for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do + test ! -f $lt_ac_sed && continue + cat /dev/null > conftest.in + lt_ac_count=0 + echo $ECHO_N "0123456789$ECHO_C" >conftest.in + # Check for GNU sed and select it if it is found. + if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then + lt_cv_path_SED=$lt_ac_sed + break + fi + while true; do + cat conftest.in conftest.in >conftest.tmp + mv conftest.tmp conftest.in + cp conftest.in conftest.nl + echo >>conftest.nl + $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break + cmp -s conftest.out conftest.nl || break + # 10000 chars as input seems more than enough + test $lt_ac_count -gt 10 && break + lt_ac_count=`expr $lt_ac_count + 1` + if test $lt_ac_count -gt $lt_ac_max; then + lt_ac_max=$lt_ac_count + lt_cv_path_SED=$lt_ac_sed + fi + done +done + +fi + +SED=$lt_cv_path_SED + +{ echo "$as_me:$LINENO: result: $SED" >&5 +echo "${ECHO_T}$SED" >&6; } + +{ echo "$as_me:$LINENO: checking for grep that handles long lines and -e" >&5 +echo $ECHO_N "checking for grep that handles long lines and -e... $ECHO_C" >&6; } +if test "${ac_cv_path_GREP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # Extract the first word of "grep ggrep" to use in msg output +if test -z "$GREP"; then +set dummy grep ggrep; ac_prog_name=$2 +if test "${ac_cv_path_GREP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + 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" + { test -f "$ac_path_GREP" && $as_test_x "$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 + echo $ECHO_N "0123456789$ECHO_C" >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + 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 + ac_count=`expr $ac_count + 1` + 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 + + +fi + +GREP="$ac_cv_path_GREP" +if test -z "$GREP"; then + { { echo "$as_me:$LINENO: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5 +echo "$as_me: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;} + { (exit 1); exit 1; }; } +fi + +else + ac_cv_path_GREP=$GREP +fi + + +fi +{ echo "$as_me:$LINENO: result: $ac_cv_path_GREP" >&5 +echo "${ECHO_T}$ac_cv_path_GREP" >&6; } + GREP="$ac_cv_path_GREP" + + +{ echo "$as_me:$LINENO: checking for egrep" >&5 +echo $ECHO_N "checking for egrep... $ECHO_C" >&6; } +if test "${ac_cv_path_EGREP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 + then ac_cv_path_EGREP="$GREP -E" + else + # Extract the first word of "egrep" to use in msg output +if test -z "$EGREP"; then +set dummy egrep; ac_prog_name=$2 +if test "${ac_cv_path_EGREP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + 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" + { test -f "$ac_path_EGREP" && $as_test_x "$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 + echo $ECHO_N "0123456789$ECHO_C" >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + 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 + ac_count=`expr $ac_count + 1` + 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 + + +fi + +EGREP="$ac_cv_path_EGREP" +if test -z "$EGREP"; then + { { echo "$as_me:$LINENO: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5 +echo "$as_me: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;} + { (exit 1); exit 1; }; } +fi + +else + ac_cv_path_EGREP=$EGREP +fi + + + fi +fi +{ echo "$as_me:$LINENO: result: $ac_cv_path_EGREP" >&5 +echo "${ECHO_T}$ac_cv_path_EGREP" >&6; } + EGREP="$ac_cv_path_EGREP" + + + +# Check whether --with-gnu-ld was given. +if test "${with_gnu_ld+set}" = set; then + withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes +else + with_gnu_ld=no +fi + +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + { echo "$as_me:$LINENO: checking for ld used by $CC" >&5 +echo $ECHO_N "checking for ld used by $CC... $ECHO_C" >&6; } + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [\\/]* | ?:[\\/]*) + re_direlt='/[^/][^/]*/\.\./' + # Canonicalize the pathname of ld + ac_prog=`echo $ac_prog| $SED 's%\\\\%/%g'` + while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do + ac_prog=`echo $ac_prog| $SED "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + { echo "$as_me:$LINENO: checking for GNU ld" >&5 +echo $ECHO_N "checking for GNU ld... $ECHO_C" >&6; } +else + { echo "$as_me:$LINENO: checking for non-GNU ld" >&5 +echo $ECHO_N "checking for non-GNU ld... $ECHO_C" >&6; } +fi +if test "${lt_cv_path_LD+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -z "$LD"; then + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some variants of GNU ld only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$lt_cv_path_LD" -v 2>&1 &5 +echo "${ECHO_T}$LD" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi +test -z "$LD" && { { echo "$as_me:$LINENO: error: no acceptable ld found in \$PATH" >&5 +echo "$as_me: error: no acceptable ld found in \$PATH" >&2;} + { (exit 1); exit 1; }; } +{ echo "$as_me:$LINENO: checking if the linker ($LD) is GNU ld" >&5 +echo $ECHO_N "checking if the linker ($LD) is GNU ld... $ECHO_C" >&6; } +if test "${lt_cv_prog_gnu_ld+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # I'd rather use --version here, but apparently some GNU lds only accept -v. +case `$LD -v 2>&1 &5 +echo "${ECHO_T}$lt_cv_prog_gnu_ld" >&6; } +with_gnu_ld=$lt_cv_prog_gnu_ld + + +{ echo "$as_me:$LINENO: checking for $LD option to reload object files" >&5 +echo $ECHO_N "checking for $LD option to reload object files... $ECHO_C" >&6; } +if test "${lt_cv_ld_reload_flag+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_cv_ld_reload_flag='-r' +fi +{ echo "$as_me:$LINENO: result: $lt_cv_ld_reload_flag" >&5 +echo "${ECHO_T}$lt_cv_ld_reload_flag" >&6; } +reload_flag=$lt_cv_ld_reload_flag +case $reload_flag in +"" | " "*) ;; +*) reload_flag=" $reload_flag" ;; +esac +reload_cmds='$LD$reload_flag -o $output$reload_objs' +case $host_os in + darwin*) + if test "$GCC" = yes; then + reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs' + else + reload_cmds='$LD$reload_flag -o $output$reload_objs' + fi + ;; +esac + +{ echo "$as_me:$LINENO: checking for BSD-compatible nm" >&5 +echo $ECHO_N "checking for BSD-compatible nm... $ECHO_C" >&6; } +if test "${lt_cv_path_NM+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$NM"; then + # Let the user override the test. + lt_cv_path_NM="$NM" +else + lt_nm_to_check="${ac_tool_prefix}nm" + if test -n "$ac_tool_prefix" && test "$build" = "$host"; then + lt_nm_to_check="$lt_nm_to_check nm" + fi + for lt_tmp_nm in $lt_nm_to_check; do + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + tmp_nm="$ac_dir/$lt_tmp_nm" + if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then + # Check to see if the nm accepts a BSD-compat flag. + # Adding the `sed 1q' prevents false positives on HP-UX, which says: + # nm: unknown option "B" ignored + # Tru64's nm complains that /dev/null is an invalid object file + case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in + */dev/null* | *'Invalid file or object type'*) + lt_cv_path_NM="$tmp_nm -B" + break + ;; + *) + case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in + */dev/null*) + lt_cv_path_NM="$tmp_nm -p" + break + ;; + *) + lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but + continue # so that we can try to find one that supports BSD flags + ;; + esac + ;; + esac + fi + done + IFS="$lt_save_ifs" + done + test -z "$lt_cv_path_NM" && lt_cv_path_NM=nm +fi +fi +{ echo "$as_me:$LINENO: result: $lt_cv_path_NM" >&5 +echo "${ECHO_T}$lt_cv_path_NM" >&6; } +NM="$lt_cv_path_NM" + +{ echo "$as_me:$LINENO: checking how to recognize dependent libraries" >&5 +echo $ECHO_N "checking how to recognize dependent libraries... $ECHO_C" >&6; } +if test "${lt_cv_deplibs_check_method+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_cv_file_magic_cmd='$MAGIC_CMD' +lt_cv_file_magic_test_file= +lt_cv_deplibs_check_method='unknown' +# Need to set the preceding variable on all platforms that support +# interlibrary dependencies. +# 'none' -- dependencies not supported. +# `unknown' -- same as none, but documents that we really don't know. +# 'pass_all' -- all dependencies passed with no checks. +# 'test_compile' -- check by making test program. +# 'file_magic [[regex]]' -- check by looking for files in library path +# which responds to the $file_magic_cmd with a given extended regex. +# If you have `file' or equivalent on your system and you're not sure +# whether `pass_all' will *always* work, you probably want this one. + +case $host_os in +aix[4-9]*) + lt_cv_deplibs_check_method=pass_all + ;; + +beos*) + lt_cv_deplibs_check_method=pass_all + ;; + +bsdi[45]*) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)' + lt_cv_file_magic_cmd='/usr/bin/file -L' + lt_cv_file_magic_test_file=/shlib/libc.so + ;; + +cygwin*) + # func_win32_libid is a shell function defined in ltmain.sh + lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' + lt_cv_file_magic_cmd='func_win32_libid' + ;; + +mingw* | pw32*) + # Base MSYS/MinGW do not provide the 'file' command needed by + # func_win32_libid shell function, so use a weaker test based on 'objdump', + # unless we find 'file', for example because we are cross-compiling. + if ( file / ) >/dev/null 2>&1; then + lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' + lt_cv_file_magic_cmd='func_win32_libid' + else + lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?' + lt_cv_file_magic_cmd='$OBJDUMP -f' + fi + ;; + +darwin* | rhapsody*) + lt_cv_deplibs_check_method=pass_all + ;; + +freebsd* | dragonfly*) + if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then + case $host_cpu in + i*86 ) + # Not sure whether the presence of OpenBSD here was a mistake. + # Let's accept both of them until this is cleared up. + lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[3-9]86 (compact )?demand paged shared library' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` + ;; + esac + else + lt_cv_deplibs_check_method=pass_all + fi + ;; + +gnu*) + lt_cv_deplibs_check_method=pass_all + ;; + +hpux10.20* | hpux11*) + lt_cv_file_magic_cmd=/usr/bin/file + case $host_cpu in + ia64*) + lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64' + lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so + ;; + hppa*64*) + lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - PA-RISC [0-9].[0-9]' + lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl + ;; + *) + lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9].[0-9]) shared library' + lt_cv_file_magic_test_file=/usr/lib/libc.sl + ;; + esac + ;; + +interix[3-9]*) + # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|\.a)$' + ;; + +irix5* | irix6* | nonstopux*) + case $LD in + *-32|*"-32 ") libmagic=32-bit;; + *-n32|*"-n32 ") libmagic=N32;; + *-64|*"-64 ") libmagic=64-bit;; + *) libmagic=never-match;; + esac + lt_cv_deplibs_check_method=pass_all + ;; + +# This must be Linux ELF. +linux* | k*bsd*-gnu) + lt_cv_deplibs_check_method=pass_all + ;; + +netbsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|_pic\.a)$' + fi + ;; + +newos6*) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=/usr/lib/libnls.so + ;; + +nto-qnx*) + lt_cv_deplibs_check_method=unknown + ;; + +openbsd*) + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' + fi + ;; + +osf3* | osf4* | osf5*) + lt_cv_deplibs_check_method=pass_all + ;; + +rdos*) + lt_cv_deplibs_check_method=pass_all + ;; + +solaris*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv4 | sysv4.3*) + case $host_vendor in + motorola) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]' + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` + ;; + ncr) + lt_cv_deplibs_check_method=pass_all + ;; + sequent) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )' + ;; + sni) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib" + lt_cv_file_magic_test_file=/lib/libc.so + ;; + siemens) + lt_cv_deplibs_check_method=pass_all + ;; + pc) + lt_cv_deplibs_check_method=pass_all + ;; + esac + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + lt_cv_deplibs_check_method=pass_all + ;; +esac + +fi +{ echo "$as_me:$LINENO: result: $lt_cv_deplibs_check_method" >&5 +echo "${ECHO_T}$lt_cv_deplibs_check_method" >&6; } +file_magic_cmd=$lt_cv_file_magic_cmd +deplibs_check_method=$lt_cv_deplibs_check_method +test -z "$deplibs_check_method" && deplibs_check_method=unknown + + + + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC + + +# Check whether --enable-libtool-lock was given. +if test "${enable_libtool_lock+set}" = set; then + enableval=$enable_libtool_lock; +fi + +test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes + +# Some flags need to be propagated to the compiler or linker for good +# libtool support. +case $host in +ia64-*-hpux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + case `/usr/bin/file conftest.$ac_objext` in + *ELF-32*) + HPUX_IA64_MODE="32" + ;; + *ELF-64*) + HPUX_IA64_MODE="64" + ;; + esac + fi + rm -rf conftest* + ;; +*-*-irix6*) + # Find out which ABI we are using. + echo '#line 4521 "configure"' > conftest.$ac_ext + if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + if test "$lt_cv_prog_gnu_ld" = yes; then + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -melf32bsmip" + ;; + *N32*) + LD="${LD-ld} -melf32bmipn32" + ;; + *64-bit*) + LD="${LD-ld} -melf64bmip" + ;; + esac + else + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -32" + ;; + *N32*) + LD="${LD-ld} -n32" + ;; + *64-bit*) + LD="${LD-ld} -64" + ;; + esac + fi + fi + rm -rf conftest* + ;; + +x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \ +s390*-*linux*|sparc*-*linux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + case `/usr/bin/file conftest.o` in + *32-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_i386_fbsd" + ;; + x86_64-*linux*) + LD="${LD-ld} -m elf_i386" + ;; + ppc64-*linux*|powerpc64-*linux*) + LD="${LD-ld} -m elf32ppclinux" + ;; + s390x-*linux*) + LD="${LD-ld} -m elf_s390" + ;; + sparc64-*linux*) + LD="${LD-ld} -m elf32_sparc" + ;; + esac + ;; + *64-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_x86_64_fbsd" + ;; + x86_64-*linux*) + LD="${LD-ld} -m elf_x86_64" + ;; + ppc*-*linux*|powerpc*-*linux*) + LD="${LD-ld} -m elf64ppc" + ;; + s390*-*linux*) + LD="${LD-ld} -m elf64_s390" + ;; + sparc*-*linux*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; + +*-*-sco3.2v5*) + # On SCO OpenServer 5, we need -belf to get full-featured binaries. + SAVE_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -belf" + { echo "$as_me:$LINENO: checking whether the C compiler needs -belf" >&5 +echo $ECHO_N "checking whether the C compiler needs -belf... $ECHO_C" >&6; } +if test "${lt_cv_cc_needs_belf+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + 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 + + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + lt_cv_cc_needs_belf=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + lt_cv_cc_needs_belf=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext + 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 + +fi +{ echo "$as_me:$LINENO: result: $lt_cv_cc_needs_belf" >&5 +echo "${ECHO_T}$lt_cv_cc_needs_belf" >&6; } + if test x"$lt_cv_cc_needs_belf" != x"yes"; then + # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf + CFLAGS="$SAVE_CFLAGS" + fi + ;; +sparc*-*solaris*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + case `/usr/bin/file conftest.o` in + *64-bit*) + case $lt_cv_prog_gnu_ld in + yes*) LD="${LD-ld} -m elf64_sparc" ;; + *) + if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then + LD="${LD-ld} -64" + fi + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; + + +esac + +need_locks="$enable_libtool_lock" + + +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 +{ echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5 +echo $ECHO_N "checking how to run the C preprocessor... $ECHO_C" >&6; } +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then + if test "${ac_cv_prog_CPP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # Double quotes because CPP needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" + do + ac_preproc_ok=false +for ac_c_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 >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Broken: fails on valid input. +continue +fi + +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then + # Broken: success on invalid input. +continue +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Passes both tests. +ac_preproc_ok=: +break +fi + +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + break +fi + + done + ac_cv_prog_CPP=$CPP + +fi + CPP=$ac_cv_prog_CPP +else + ac_cv_prog_CPP=$CPP +fi +{ echo "$as_me:$LINENO: result: $CPP" >&5 +echo "${ECHO_T}$CPP" >&6; } +ac_preproc_ok=false +for ac_c_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 >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Broken: fails on valid input. +continue +fi + +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then + # Broken: success on invalid input. +continue +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Passes both tests. +ac_preproc_ok=: +break +fi + +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + : +else + { { echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details." >&5 +echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +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 + + +{ echo "$as_me:$LINENO: checking for ANSI C header files" >&5 +echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6; } +if test "${ac_cv_header_stdc+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#include +#include + +int +main () +{ + + ; + return 0; +} +_ACEOF +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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_header_stdc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + 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 >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* 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 >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* 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 >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* 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 +rm -f conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +ac_cv_header_stdc=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi + + +fi +fi +{ echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5 +echo "${ECHO_T}$ac_cv_header_stdc" >&6; } +if test $ac_cv_header_stdc = yes; then + +cat >>confdefs.h <<\_ACEOF +#define STDC_HEADERS 1 +_ACEOF + +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=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +{ echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + +#include <$ac_header> +_ACEOF +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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + eval "$as_ac_Header=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + eval "$as_ac_Header=no" +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +ac_res=`eval echo '${'$as_ac_Header'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + + +for ac_header in dlfcn.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + { echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +ac_res=`eval echo '${'$as_ac_Header'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +else + # Is the header compilable? +{ echo "$as_me:$LINENO: checking $ac_header usability" >&5 +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_compiler=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6; } + +# Is the header present? +{ echo "$as_me:$LINENO: checking $ac_header presence" >&5 +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi + +rm -f conftest.err conftest.$ac_ext +{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6; } + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + ( cat <<\_ASBOX +## ----------------------------------------- ## +## Report this to ntfs-3g-devel@lists.sf.net ## +## ----------------------------------------- ## +_ASBOX + ) | sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +{ echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +ac_res=`eval echo '${'$as_ac_Header'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } + +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + +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 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_CXX+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&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 { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" + echo "$as_me:$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 + { echo "$as_me:$LINENO: result: $CXX" >&5 +echo "${ECHO_T}$CXX" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}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 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_ac_ct_CXX+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&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 { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CXX="$ac_prog" + echo "$as_me:$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 + { echo "$as_me:$LINENO: result: $ac_ct_CXX" >&5 +echo "${ECHO_T}$ac_ct_CXX" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}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:) +{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&5 +echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&2;} +ac_tool_warned=yes ;; +esac + CXX=$ac_ct_CXX + fi +fi + + fi +fi +# Provide some information about the compiler. +echo "$as_me:$LINENO: checking for C++ compiler version" >&5 +ac_compiler=`set X $ac_compile; echo $2` +{ (ac_try="$ac_compiler --version >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compiler --version >&5") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (ac_try="$ac_compiler -v >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compiler -v >&5") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (ac_try="$ac_compiler -V >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compiler -V >&5") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + +{ echo "$as_me:$LINENO: checking whether we are using the GNU C++ compiler" >&5 +echo $ECHO_N "checking whether we are using the GNU C++ compiler... $ECHO_C" >&6; } +if test "${ac_cv_cxx_compiler_gnu+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_compiler_gnu=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + 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 +{ echo "$as_me:$LINENO: result: $ac_cv_cxx_compiler_gnu" >&5 +echo "${ECHO_T}$ac_cv_cxx_compiler_gnu" >&6; } +GXX=`test $ac_compiler_gnu = yes && echo yes` +ac_test_CXXFLAGS=${CXXFLAGS+set} +ac_save_CXXFLAGS=$CXXFLAGS +{ echo "$as_me:$LINENO: checking whether $CXX accepts -g" >&5 +echo $ECHO_N "checking whether $CXX accepts -g... $ECHO_C" >&6; } +if test "${ac_cv_prog_cxx_g+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&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 >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_prog_cxx_g=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + CXXFLAGS="" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cxx_werror_flag=$ac_save_cxx_werror_flag + CXXFLAGS="-g" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_prog_cxx_g=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +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 +{ echo "$as_me:$LINENO: result: $ac_cv_prog_cxx_g" >&5 +echo "${ECHO_T}$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=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 + +depcc="$CXX" am_compiler_list= + +{ echo "$as_me:$LINENO: checking dependency style of $depcc" >&5 +echo $ECHO_N "checking dependency style of $depcc... $ECHO_C" >&6; } +if test "${am_cv_CXX_dependencies_compiler_type+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&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'. + 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 + 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 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + case $depmode in + 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 + ;; + none) break ;; + esac + # 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. + if depmode=$depmode \ + source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} 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 sub/conftest.${OBJEXT-o} 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 +{ echo "$as_me:$LINENO: result: $am_cv_CXX_dependencies_compiler_type" >&5 +echo "${ECHO_T}$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 + + + + +if test -n "$CXX" && ( test "X$CXX" != "Xno" && + ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || + (test "X$CXX" != "Xg++"))) ; then + 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 +{ echo "$as_me:$LINENO: checking how to run the C++ preprocessor" >&5 +echo $ECHO_N "checking how to run the C++ preprocessor... $ECHO_C" >&6; } +if test -z "$CXXCPP"; then + if test "${ac_cv_prog_CXXCPP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&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 >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" || + test ! -s conftest.err + }; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Broken: fails on valid input. +continue +fi + +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" || + test ! -s conftest.err + }; then + # Broken: success on invalid input. +continue +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Passes both tests. +ac_preproc_ok=: +break +fi + +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f 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 +{ echo "$as_me:$LINENO: result: $CXXCPP" >&5 +echo "${ECHO_T}$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 >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" || + test ! -s conftest.err + }; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Broken: fails on valid input. +continue +fi + +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" || + test ! -s conftest.err + }; then + # Broken: success on invalid input. +continue +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Passes both tests. +ac_preproc_ok=: +break +fi + +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + : +else + { { echo "$as_me:$LINENO: error: C++ preprocessor \"$CXXCPP\" fails sanity check +See \`config.log' for more details." >&5 +echo "$as_me: error: C++ preprocessor \"$CXXCPP\" fails sanity check +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +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 + +fi + + +ac_ext=f +ac_compile='$F77 -c $FFLAGS conftest.$ac_ext >&5' +ac_link='$F77 -o conftest$ac_exeext $FFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_f77_compiler_gnu +if test -n "$ac_tool_prefix"; then + for ac_prog in g77 xlf f77 frt pgf77 cf77 fort77 fl32 af77 xlf90 f90 pgf90 pghpf epcf90 gfortran g95 xlf95 f95 fort ifort ifc efc pgf95 lf95 ftn + 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 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_F77+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$F77"; then + ac_cv_prog_F77="$F77" # 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 { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_F77="$ac_tool_prefix$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +F77=$ac_cv_prog_F77 +if test -n "$F77"; then + { echo "$as_me:$LINENO: result: $F77" >&5 +echo "${ECHO_T}$F77" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + + test -n "$F77" && break + done +fi +if test -z "$F77"; then + ac_ct_F77=$F77 + for ac_prog in g77 xlf f77 frt pgf77 cf77 fort77 fl32 af77 xlf90 f90 pgf90 pghpf epcf90 gfortran g95 xlf95 f95 fort ifort ifc efc pgf95 lf95 ftn +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_ac_ct_F77+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_F77"; then + ac_cv_prog_ac_ct_F77="$ac_ct_F77" # 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 { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_F77="$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +ac_ct_F77=$ac_cv_prog_ac_ct_F77 +if test -n "$ac_ct_F77"; then + { echo "$as_me:$LINENO: result: $ac_ct_F77" >&5 +echo "${ECHO_T}$ac_ct_F77" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + + test -n "$ac_ct_F77" && break +done + + if test "x$ac_ct_F77" = x; then + F77="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&5 +echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&2;} +ac_tool_warned=yes ;; +esac + F77=$ac_ct_F77 + fi +fi + + +# Provide some information about the compiler. +echo "$as_me:$LINENO: checking for Fortran 77 compiler version" >&5 +ac_compiler=`set X $ac_compile; echo $2` +{ (ac_try="$ac_compiler --version >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compiler --version >&5") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (ac_try="$ac_compiler -v >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compiler -v >&5") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (ac_try="$ac_compiler -V >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compiler -V >&5") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +rm -f a.out + +# If we don't use `.F' as extension, the preprocessor is not run on the +# input file. (Note that this only needs to work for GNU compilers.) +ac_save_ext=$ac_ext +ac_ext=F +{ echo "$as_me:$LINENO: checking whether we are using the GNU Fortran 77 compiler" >&5 +echo $ECHO_N "checking whether we are using the GNU Fortran 77 compiler... $ECHO_C" >&6; } +if test "${ac_cv_f77_compiler_gnu+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF + program main +#ifndef __GNUC__ + choke me +#endif + + end +_ACEOF +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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_f77_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_compiler_gnu=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_compiler_gnu=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_f77_compiler_gnu=$ac_compiler_gnu + +fi +{ echo "$as_me:$LINENO: result: $ac_cv_f77_compiler_gnu" >&5 +echo "${ECHO_T}$ac_cv_f77_compiler_gnu" >&6; } +ac_ext=$ac_save_ext +ac_test_FFLAGS=${FFLAGS+set} +ac_save_FFLAGS=$FFLAGS +FFLAGS= +{ echo "$as_me:$LINENO: checking whether $F77 accepts -g" >&5 +echo $ECHO_N "checking whether $F77 accepts -g... $ECHO_C" >&6; } +if test "${ac_cv_prog_f77_g+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + FFLAGS=-g +cat >conftest.$ac_ext <<_ACEOF + program main + + end +_ACEOF +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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_f77_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_prog_f77_g=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_prog_f77_g=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +fi +{ echo "$as_me:$LINENO: result: $ac_cv_prog_f77_g" >&5 +echo "${ECHO_T}$ac_cv_prog_f77_g" >&6; } +if test "$ac_test_FFLAGS" = set; then + FFLAGS=$ac_save_FFLAGS +elif test $ac_cv_prog_f77_g = yes; then + if test "x$ac_cv_f77_compiler_gnu" = xyes; then + FFLAGS="-g -O2" + else + FFLAGS="-g" + fi +else + if test "x$ac_cv_f77_compiler_gnu" = xyes; then + FFLAGS="-O2" + else + FFLAGS= + fi +fi + +G77=`test $ac_compiler_gnu = yes && echo yes` +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 + + + +# Autoconf 2.13's AC_OBJEXT and AC_EXEEXT macros only works for C compilers! +# find the maximum length of command line arguments +{ echo "$as_me:$LINENO: checking the maximum length of command line arguments" >&5 +echo $ECHO_N "checking the maximum length of command line arguments... $ECHO_C" >&6; } +if test "${lt_cv_sys_max_cmd_len+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + i=0 + teststring="ABCD" + + case $build_os in + msdosdjgpp*) + # On DJGPP, this test can blow up pretty badly due to problems in libc + # (any single argument exceeding 2000 bytes causes a buffer overrun + # during glob expansion). Even if it were fixed, the result of this + # check would be larger than it should be. + lt_cv_sys_max_cmd_len=12288; # 12K is about right + ;; + + gnu*) + # Under GNU Hurd, this test is not required because there is + # no limit to the length of command line arguments. + # Libtool will interpret -1 as no limit whatsoever + lt_cv_sys_max_cmd_len=-1; + ;; + + cygwin* | mingw*) + # On Win9x/ME, this test blows up -- it succeeds, but takes + # about 5 minutes as the teststring grows exponentially. + # Worse, since 9x/ME are not pre-emptively multitasking, + # you end up with a "frozen" computer, even though with patience + # the test eventually succeeds (with a max line length of 256k). + # Instead, let's just punt: use the minimum linelength reported by + # all of the supported platforms: 8192 (on NT/2K/XP). + lt_cv_sys_max_cmd_len=8192; + ;; + + amigaos*) + # On AmigaOS with pdksh, this test takes hours, literally. + # So we just punt and use a minimum line length of 8192. + lt_cv_sys_max_cmd_len=8192; + ;; + + netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) + # This has been around since 386BSD, at least. Likely further. + if test -x /sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` + elif test -x /usr/sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` + else + lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs + fi + # And add a safety zone + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + ;; + + interix*) + # We know the value 262144 and hardcode it with a safety zone (like BSD) + lt_cv_sys_max_cmd_len=196608 + ;; + + osf*) + # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure + # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not + # nice to cause kernel panics so lets avoid the loop below. + # First set a reasonable default. + lt_cv_sys_max_cmd_len=16384 + # + if test -x /sbin/sysconfig; then + case `/sbin/sysconfig -q proc exec_disable_arg_limit` in + *1*) lt_cv_sys_max_cmd_len=-1 ;; + esac + fi + ;; + sco3.2v5*) + lt_cv_sys_max_cmd_len=102400 + ;; + sysv5* | sco5v6* | sysv4.2uw2*) + kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` + if test -n "$kargmax"; then + lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[ ]//'` + else + lt_cv_sys_max_cmd_len=32768 + fi + ;; + *) + lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` + if test -n "$lt_cv_sys_max_cmd_len"; then + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + else + SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} + while (test "X"`$SHELL $0 --fallback-echo "X$teststring" 2>/dev/null` \ + = "XX$teststring") >/dev/null 2>&1 && + new_result=`expr "X$teststring" : ".*" 2>&1` && + lt_cv_sys_max_cmd_len=$new_result && + test $i != 17 # 1/2 MB should be enough + do + i=`expr $i + 1` + teststring=$teststring$teststring + done + teststring= + # Add a significant safety factor because C++ compilers can tack on massive + # amounts of additional arguments before passing them to the linker. + # It appears as though 1/2 is a usable value. + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` + fi + ;; + esac + +fi + +if test -n $lt_cv_sys_max_cmd_len ; then + { echo "$as_me:$LINENO: result: $lt_cv_sys_max_cmd_len" >&5 +echo "${ECHO_T}$lt_cv_sys_max_cmd_len" >&6; } +else + { echo "$as_me:$LINENO: result: none" >&5 +echo "${ECHO_T}none" >&6; } +fi + + + + + +# Check for command to grab the raw symbol name followed by C symbol from nm. +{ echo "$as_me:$LINENO: checking command to parse $NM output from $compiler object" >&5 +echo $ECHO_N "checking command to parse $NM output from $compiler object... $ECHO_C" >&6; } +if test "${lt_cv_sys_global_symbol_pipe+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + +# These are sane defaults that work on at least a few old systems. +# [They come from Ultrix. What could be older than Ultrix?!! ;)] + +# Character class describing NM global symbol codes. +symcode='[BCDEGRST]' + +# Regexp to match symbols that can be accessed directly from C. +sympat='\([_A-Za-z][_A-Za-z0-9]*\)' + +# Transform an extracted symbol line into a proper C declaration +lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^. .* \(.*\)$/extern int \1;/p'" + +# Transform an extracted symbol line into symbol name and symbol address +lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode \([^ ]*\) \([^ ]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" + +# Define system-specific variables. +case $host_os in +aix*) + symcode='[BCDT]' + ;; +cygwin* | mingw* | pw32*) + symcode='[ABCDGISTW]' + ;; +hpux*) # Its linker distinguishes data from code symbols + if test "$host_cpu" = ia64; then + symcode='[ABCDEGRST]' + fi + lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" + lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" + ;; +linux* | k*bsd*-gnu) + if test "$host_cpu" = ia64; then + symcode='[ABCDGIRSTW]' + lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" + lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" + fi + ;; +irix* | nonstopux*) + symcode='[BCDEGRST]' + ;; +osf*) + symcode='[BCDEGQRST]' + ;; +solaris*) + symcode='[BDRT]' + ;; +sco3.2v5*) + symcode='[DT]' + ;; +sysv4.2uw2*) + symcode='[DT]' + ;; +sysv5* | sco5v6* | unixware* | OpenUNIX*) + symcode='[ABDT]' + ;; +sysv4) + symcode='[DFNSTU]' + ;; +esac + +# Handle CRLF in mingw tool chain +opt_cr= +case $build_os in +mingw*) + opt_cr=`echo 'x\{0,1\}' | tr x '\015'` # option cr in regexp + ;; +esac + +# If we're using GNU nm, then use its standard symbol codes. +case `$NM -V 2>&1` in +*GNU* | *'with BFD'*) + symcode='[ABCDGIRSTW]' ;; +esac + +# Try without a prefix undercore, then with it. +for ac_symprfx in "" "_"; do + + # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. + symxfrm="\\1 $ac_symprfx\\2 \\2" + + # Write the raw and C identifiers. + lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" + + # Check to see that the pipe works correctly. + pipe_works=no + + rm -f conftest* + cat > conftest.$ac_ext <&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # Now try to grab the symbols. + nlist=conftest.nm + if { (eval echo "$as_me:$LINENO: \"$NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist\"") >&5 + (eval $NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && test -s "$nlist"; then + # Try sorting and uniquifying the output. + if sort "$nlist" | uniq > "$nlist"T; then + mv -f "$nlist"T "$nlist" + else + rm -f "$nlist"T + fi + + # Make sure that we snagged all the symbols we need. + if grep ' nm_test_var$' "$nlist" >/dev/null; then + if grep ' nm_test_func$' "$nlist" >/dev/null; then + cat < conftest.$ac_ext +#ifdef __cplusplus +extern "C" { +#endif + +EOF + # Now generate the symbol file. + eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | grep -v main >> conftest.$ac_ext' + + cat <> conftest.$ac_ext +#if defined (__STDC__) && __STDC__ +# define lt_ptr_t void * +#else +# define lt_ptr_t char * +# define const +#endif + +/* The mapping between symbol names and symbols. */ +const struct { + const char *name; + lt_ptr_t address; +} +lt_preloaded_symbols[] = +{ +EOF + $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (lt_ptr_t) \&\2},/" < "$nlist" | grep -v main >> conftest.$ac_ext + cat <<\EOF >> conftest.$ac_ext + {0, (lt_ptr_t) 0} +}; + +#ifdef __cplusplus +} +#endif +EOF + # Now try linking the two files. + mv conftest.$ac_objext conftstm.$ac_objext + lt_save_LIBS="$LIBS" + lt_save_CFLAGS="$CFLAGS" + LIBS="conftstm.$ac_objext" + CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag" + if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && test -s conftest${ac_exeext}; then + pipe_works=yes + fi + LIBS="$lt_save_LIBS" + CFLAGS="$lt_save_CFLAGS" + else + echo "cannot find nm_test_func in $nlist" >&5 + fi + else + echo "cannot find nm_test_var in $nlist" >&5 + fi + else + echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5 + fi + else + echo "$progname: failed program was:" >&5 + cat conftest.$ac_ext >&5 + fi + rm -rf conftest* conftst* + + # Do not use the global_symbol_pipe unless it works. + if test "$pipe_works" = yes; then + break + else + lt_cv_sys_global_symbol_pipe= + fi +done + +fi + +if test -z "$lt_cv_sys_global_symbol_pipe"; then + lt_cv_sys_global_symbol_to_cdecl= +fi +if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then + { echo "$as_me:$LINENO: result: failed" >&5 +echo "${ECHO_T}failed" >&6; } +else + { echo "$as_me:$LINENO: result: ok" >&5 +echo "${ECHO_T}ok" >&6; } +fi + +{ echo "$as_me:$LINENO: checking for objdir" >&5 +echo $ECHO_N "checking for objdir... $ECHO_C" >&6; } +if test "${lt_cv_objdir+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + rm -f .libs 2>/dev/null +mkdir .libs 2>/dev/null +if test -d .libs; then + lt_cv_objdir=.libs +else + # MS-DOS does not allow filenames that begin with a dot. + lt_cv_objdir=_libs +fi +rmdir .libs 2>/dev/null +fi +{ echo "$as_me:$LINENO: result: $lt_cv_objdir" >&5 +echo "${ECHO_T}$lt_cv_objdir" >&6; } +objdir=$lt_cv_objdir + + + + + +case $host_os in +aix3*) + # AIX sometimes has problems with the GCC collect2 program. For some + # reason, if we set the COLLECT_NAMES environment variable, the problems + # vanish in a puff of smoke. + if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES + fi + ;; +esac + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +Xsed='sed -e 1s/^X//' +sed_quote_subst='s/\([\\"\\`$\\\\]\)/\\\1/g' + +# Same as above, but do not quote variable references. +double_quote_subst='s/\([\\"\\`\\\\]\)/\\\1/g' + +# Sed substitution to delay expansion of an escaped shell variable in a +# double_quote_subst'ed string. +delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' + +# Sed substitution to avoid accidental globbing in evaled expressions +no_glob_subst='s/\*/\\\*/g' + +# Constants: +rm="rm -f" + +# Global variables: +default_ofile=libtool +can_build_shared=yes + +# All known linkers require a `.a' archive for static linking (except MSVC, +# which needs '.lib'). +libext=a +ltmain="$ac_aux_dir/ltmain.sh" +ofile="$default_ofile" +with_gnu_ld="$lt_cv_prog_gnu_ld" + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args. +set dummy ${ac_tool_prefix}ar; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_AR+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$AR"; then + ac_cv_prog_AR="$AR" # 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 { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_AR="${ac_tool_prefix}ar" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +AR=$ac_cv_prog_AR +if test -n "$AR"; then + { echo "$as_me:$LINENO: result: $AR" >&5 +echo "${ECHO_T}$AR" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_AR"; then + ac_ct_AR=$AR + # Extract the first word of "ar", so it can be a program name with args. +set dummy ar; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_ac_ct_AR+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_AR"; then + ac_cv_prog_ac_ct_AR="$ac_ct_AR" # 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 { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_AR="ar" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +ac_ct_AR=$ac_cv_prog_ac_ct_AR +if test -n "$ac_ct_AR"; then + { echo "$as_me:$LINENO: result: $ac_ct_AR" >&5 +echo "${ECHO_T}$ac_ct_AR" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + if test "x$ac_ct_AR" = x; then + AR="false" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&5 +echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&2;} +ac_tool_warned=yes ;; +esac + AR=$ac_ct_AR + fi +else + AR="$ac_cv_prog_AR" +fi + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. +set dummy ${ac_tool_prefix}ranlib; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_RANLIB+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # 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 { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +RANLIB=$ac_cv_prog_RANLIB +if test -n "$RANLIB"; then + { echo "$as_me:$LINENO: result: $RANLIB" >&5 +echo "${ECHO_T}$RANLIB" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_RANLIB"; then + ac_ct_RANLIB=$RANLIB + # Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_RANLIB"; then + ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # 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 { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_RANLIB="ranlib" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB +if test -n "$ac_ct_RANLIB"; then + { echo "$as_me:$LINENO: result: $ac_ct_RANLIB" >&5 +echo "${ECHO_T}$ac_ct_RANLIB" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + if test "x$ac_ct_RANLIB" = x; then + RANLIB=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&5 +echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&2;} +ac_tool_warned=yes ;; +esac + RANLIB=$ac_ct_RANLIB + fi +else + RANLIB="$ac_cv_prog_RANLIB" +fi + +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 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_STRIP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&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 { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_STRIP="${ac_tool_prefix}strip" + echo "$as_me:$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 + { echo "$as_me:$LINENO: result: $STRIP" >&5 +echo "${ECHO_T}$STRIP" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}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 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&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 { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_STRIP="strip" + echo "$as_me:$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 + { echo "$as_me:$LINENO: result: $ac_ct_STRIP" >&5 +echo "${ECHO_T}$ac_ct_STRIP" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + if test "x$ac_ct_STRIP" = x; then + STRIP=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&5 +echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&2;} +ac_tool_warned=yes ;; +esac + STRIP=$ac_ct_STRIP + fi +else + STRIP="$ac_cv_prog_STRIP" +fi + + +old_CC="$CC" +old_CFLAGS="$CFLAGS" + +# Set sane defaults for various variables +test -z "$AR" && AR=ar +test -z "$AR_FLAGS" && AR_FLAGS=cru +test -z "$AS" && AS=as +test -z "$CC" && CC=cc +test -z "$LTCC" && LTCC=$CC +test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS +test -z "$DLLTOOL" && DLLTOOL=dlltool +test -z "$LD" && LD=ld +test -z "$LN_S" && LN_S="ln -s" +test -z "$MAGIC_CMD" && MAGIC_CMD=file +test -z "$NM" && NM=nm +test -z "$SED" && SED=sed +test -z "$OBJDUMP" && OBJDUMP=objdump +test -z "$RANLIB" && RANLIB=: +test -z "$STRIP" && STRIP=: +test -z "$ac_objext" && ac_objext=o + +# Determine commands to create old-style static archives. +old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' +old_postinstall_cmds='chmod 644 $oldlib' +old_postuninstall_cmds= + +if test -n "$RANLIB"; then + case $host_os in + openbsd*) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$oldlib" + ;; + *) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$oldlib" + ;; + esac + old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib" +fi + +for cc_temp in $compiler""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`$echo "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"` + + +# Only perform the check for file, if the check method requires it +case $deplibs_check_method in +file_magic*) + if test "$file_magic_cmd" = '$MAGIC_CMD'; then + { echo "$as_me:$LINENO: checking for ${ac_tool_prefix}file" >&5 +echo $ECHO_N "checking for ${ac_tool_prefix}file... $ECHO_C" >&6; } +if test "${lt_cv_path_MAGIC_CMD+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + case $MAGIC_CMD in +[\\/*] | ?:[\\/]*) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; +*) + lt_save_MAGIC_CMD="$MAGIC_CMD" + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" + for ac_dir in $ac_dummy; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/${ac_tool_prefix}file; then + lt_cv_path_MAGIC_CMD="$ac_dir/${ac_tool_prefix}file" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + $EGREP "$file_magic_regex" > /dev/null; then + : + else + cat <&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +EOF + fi ;; + esac + fi + break + fi + done + IFS="$lt_save_ifs" + MAGIC_CMD="$lt_save_MAGIC_CMD" + ;; +esac +fi + +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + { echo "$as_me:$LINENO: result: $MAGIC_CMD" >&5 +echo "${ECHO_T}$MAGIC_CMD" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + +if test -z "$lt_cv_path_MAGIC_CMD"; then + if test -n "$ac_tool_prefix"; then + { echo "$as_me:$LINENO: checking for file" >&5 +echo $ECHO_N "checking for file... $ECHO_C" >&6; } +if test "${lt_cv_path_MAGIC_CMD+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + case $MAGIC_CMD in +[\\/*] | ?:[\\/]*) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; +*) + lt_save_MAGIC_CMD="$MAGIC_CMD" + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" + for ac_dir in $ac_dummy; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/file; then + lt_cv_path_MAGIC_CMD="$ac_dir/file" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + $EGREP "$file_magic_regex" > /dev/null; then + : + else + cat <&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +EOF + fi ;; + esac + fi + break + fi + done + IFS="$lt_save_ifs" + MAGIC_CMD="$lt_save_MAGIC_CMD" + ;; +esac +fi + +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + { echo "$as_me:$LINENO: result: $MAGIC_CMD" >&5 +echo "${ECHO_T}$MAGIC_CMD" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + else + MAGIC_CMD=: + fi +fi + + fi + ;; +esac + + + case $host_os in + rhapsody* | darwin*) + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}dsymutil", so it can be a program name with args. +set dummy ${ac_tool_prefix}dsymutil; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_DSYMUTIL+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$DSYMUTIL"; then + ac_cv_prog_DSYMUTIL="$DSYMUTIL" # 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 { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_DSYMUTIL="${ac_tool_prefix}dsymutil" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +DSYMUTIL=$ac_cv_prog_DSYMUTIL +if test -n "$DSYMUTIL"; then + { echo "$as_me:$LINENO: result: $DSYMUTIL" >&5 +echo "${ECHO_T}$DSYMUTIL" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_DSYMUTIL"; then + ac_ct_DSYMUTIL=$DSYMUTIL + # Extract the first word of "dsymutil", so it can be a program name with args. +set dummy dsymutil; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_ac_ct_DSYMUTIL+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_DSYMUTIL"; then + ac_cv_prog_ac_ct_DSYMUTIL="$ac_ct_DSYMUTIL" # 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 { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_DSYMUTIL="dsymutil" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +ac_ct_DSYMUTIL=$ac_cv_prog_ac_ct_DSYMUTIL +if test -n "$ac_ct_DSYMUTIL"; then + { echo "$as_me:$LINENO: result: $ac_ct_DSYMUTIL" >&5 +echo "${ECHO_T}$ac_ct_DSYMUTIL" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + if test "x$ac_ct_DSYMUTIL" = x; then + DSYMUTIL=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&5 +echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&2;} +ac_tool_warned=yes ;; +esac + DSYMUTIL=$ac_ct_DSYMUTIL + fi +else + DSYMUTIL="$ac_cv_prog_DSYMUTIL" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}nmedit", so it can be a program name with args. +set dummy ${ac_tool_prefix}nmedit; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_NMEDIT+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$NMEDIT"; then + ac_cv_prog_NMEDIT="$NMEDIT" # 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 { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_NMEDIT="${ac_tool_prefix}nmedit" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +NMEDIT=$ac_cv_prog_NMEDIT +if test -n "$NMEDIT"; then + { echo "$as_me:$LINENO: result: $NMEDIT" >&5 +echo "${ECHO_T}$NMEDIT" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_NMEDIT"; then + ac_ct_NMEDIT=$NMEDIT + # Extract the first word of "nmedit", so it can be a program name with args. +set dummy nmedit; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_ac_ct_NMEDIT+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_NMEDIT"; then + ac_cv_prog_ac_ct_NMEDIT="$ac_ct_NMEDIT" # 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 { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_NMEDIT="nmedit" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +ac_ct_NMEDIT=$ac_cv_prog_ac_ct_NMEDIT +if test -n "$ac_ct_NMEDIT"; then + { echo "$as_me:$LINENO: result: $ac_ct_NMEDIT" >&5 +echo "${ECHO_T}$ac_ct_NMEDIT" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + if test "x$ac_ct_NMEDIT" = x; then + NMEDIT=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&5 +echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&2;} +ac_tool_warned=yes ;; +esac + NMEDIT=$ac_ct_NMEDIT + fi +else + NMEDIT="$ac_cv_prog_NMEDIT" +fi + + + { echo "$as_me:$LINENO: checking for -single_module linker flag" >&5 +echo $ECHO_N "checking for -single_module linker flag... $ECHO_C" >&6; } +if test "${lt_cv_apple_cc_single_mod+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_cv_apple_cc_single_mod=no + if test -z "${LT_MULTI_MODULE}"; then + # By default we will add the -single_module flag. You can override + # by either setting the environment variable LT_MULTI_MODULE + # non-empty at configure time, or by adding -multi_module to the + # link flags. + echo "int foo(void){return 1;}" > conftest.c + $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ + -dynamiclib ${wl}-single_module conftest.c + if test -f libconftest.dylib; then + lt_cv_apple_cc_single_mod=yes + rm -rf libconftest.dylib* + fi + rm conftest.c + fi +fi +{ echo "$as_me:$LINENO: result: $lt_cv_apple_cc_single_mod" >&5 +echo "${ECHO_T}$lt_cv_apple_cc_single_mod" >&6; } + { echo "$as_me:$LINENO: checking for -exported_symbols_list linker flag" >&5 +echo $ECHO_N "checking for -exported_symbols_list linker flag... $ECHO_C" >&6; } +if test "${lt_cv_ld_exported_symbols_list+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_cv_ld_exported_symbols_list=no + save_LDFLAGS=$LDFLAGS + echo "_main" > conftest.sym + LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + lt_cv_ld_exported_symbols_list=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + lt_cv_ld_exported_symbols_list=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext + LDFLAGS="$save_LDFLAGS" + +fi +{ echo "$as_me:$LINENO: result: $lt_cv_ld_exported_symbols_list" >&5 +echo "${ECHO_T}$lt_cv_ld_exported_symbols_list" >&6; } + case $host_os in + rhapsody* | darwin1.[0123]) + _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;; + darwin1.*) + _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; + darwin*) + # if running on 10.5 or later, the deployment target defaults + # to the OS version, if on x86, and 10.4, the deployment + # target defaults to 10.4. Don't you love it? + case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in + 10.0,*86*-darwin8*|10.0,*-darwin[91]*) + _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; + 10.[012]*) + _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; + 10.*) + _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; + esac + ;; + esac + if test "$lt_cv_apple_cc_single_mod" = "yes"; then + _lt_dar_single_mod='$single_module' + fi + if test "$lt_cv_ld_exported_symbols_list" = "yes"; then + _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym' + else + _lt_dar_export_syms="~$NMEDIT -s \$output_objdir/\${libname}-symbols.expsym \${lib}" + fi + if test "$DSYMUTIL" != ":"; then + _lt_dsymutil="~$DSYMUTIL \$lib || :" + else + _lt_dsymutil= + fi + ;; + esac + + +enable_dlopen=no +enable_win32_dll=no + +# Check whether --enable-libtool-lock was given. +if test "${enable_libtool_lock+set}" = set; then + enableval=$enable_libtool_lock; +fi + +test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes + + +# Check whether --with-pic was given. +if test "${with_pic+set}" = set; then + withval=$with_pic; pic_mode="$withval" +else + pic_mode=default +fi + +test -z "$pic_mode" && pic_mode=default + +# Use C for the default configuration in the libtool script +tagname= +lt_save_CC="$CC" +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 + + +# Source file extension for C test sources. +ac_ext=c + +# Object file extension for compiled C test sources. +objext=o +objext=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="int some_variable = 0;" + +# Code to be used in simple link tests +lt_simple_link_test_code='int main(){return(0);}' + + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC + + +# save warnings/boilerplate of simple test code +ac_outfile=conftest.$ac_objext +echo "$lt_simple_compile_test_code" >conftest.$ac_ext +eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_compiler_boilerplate=`cat conftest.err` +$rm conftest* + +ac_outfile=conftest.$ac_objext +echo "$lt_simple_link_test_code" >conftest.$ac_ext +eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_linker_boilerplate=`cat conftest.err` +$rm -r conftest* + + + +lt_prog_compiler_no_builtin_flag= + +if test "$GCC" = yes; then + lt_prog_compiler_no_builtin_flag=' -fno-builtin' + + +{ echo "$as_me:$LINENO: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 +echo $ECHO_N "checking if $compiler supports -fno-rtti -fno-exceptions... $ECHO_C" >&6; } +if test "${lt_cv_prog_compiler_rtti_exceptions+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_cv_prog_compiler_rtti_exceptions=no + ac_outfile=conftest.$ac_objext + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="-fno-rtti -fno-exceptions" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:7578: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:7582: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_rtti_exceptions=yes + fi + fi + $rm conftest* + +fi +{ echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_rtti_exceptions" >&5 +echo "${ECHO_T}$lt_cv_prog_compiler_rtti_exceptions" >&6; } + +if test x"$lt_cv_prog_compiler_rtti_exceptions" = xyes; then + lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions" +else + : +fi + +fi + +lt_prog_compiler_wl= +lt_prog_compiler_pic= +lt_prog_compiler_static= + +{ echo "$as_me:$LINENO: checking for $compiler option to produce PIC" >&5 +echo $ECHO_N "checking for $compiler option to produce PIC... $ECHO_C" >&6; } + + if test "$GCC" = yes; then + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_static='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static='-Bstatic' + fi + ;; + + amigaos*) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4' + ;; + + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + + mingw* | cygwin* | pw32* | os2*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + # Although the cygwin gcc ignores -fPIC, still need this for old-style + # (--disable-auto-import) libraries + lt_prog_compiler_pic='-DDLL_EXPORT' + ;; + + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + lt_prog_compiler_pic='-fno-common' + ;; + + interix[3-9]*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + + msdosdjgpp*) + # Just because we use GCC doesn't mean we suddenly get shared libraries + # on systems that don't support them. + lt_prog_compiler_can_build_shared=no + enable_shared=no + ;; + + sysv4*MP*) + if test -d /usr/nec; then + lt_prog_compiler_pic=-Kconform_pic + fi + ;; + + hpux*) + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic='-fPIC' + ;; + esac + ;; + + *) + lt_prog_compiler_pic='-fPIC' + ;; + esac + else + # PORTME Check for flag to pass linker flags through the system compiler. + case $host_os in + aix*) + lt_prog_compiler_wl='-Wl,' + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static='-Bstatic' + else + lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp' + fi + ;; + darwin*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + case $cc_basename in + xlc*) + lt_prog_compiler_pic='-qnocommon' + lt_prog_compiler_wl='-Wl,' + ;; + esac + ;; + + mingw* | cygwin* | pw32* | os2*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + lt_prog_compiler_pic='-DDLL_EXPORT' + ;; + + hpux9* | hpux10* | hpux11*) + lt_prog_compiler_wl='-Wl,' + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic='+Z' + ;; + esac + # Is there a better lt_prog_compiler_static that works with the bundled CC? + lt_prog_compiler_static='${wl}-a ${wl}archive' + ;; + + irix5* | irix6* | nonstopux*) + lt_prog_compiler_wl='-Wl,' + # PIC (with -KPIC) is the default. + lt_prog_compiler_static='-non_shared' + ;; + + newsos6) + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + ;; + + linux* | k*bsd*-gnu) + case $cc_basename in + icc* | ecc*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-static' + ;; + pgcc* | pgf77* | pgf90* | pgf95*) + # Portland Group compilers (*not* the Pentium gcc compiler, + # which looks to be a dead project) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-fpic' + lt_prog_compiler_static='-Bstatic' + ;; + ccc*) + lt_prog_compiler_wl='-Wl,' + # All Alpha code is PIC. + lt_prog_compiler_static='-non_shared' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C 5.9 + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + lt_prog_compiler_wl='-Wl,' + ;; + *Sun\ F*) + # Sun Fortran 8.3 passes all unrecognized flags to the linker + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + lt_prog_compiler_wl='' + ;; + esac + ;; + esac + ;; + + osf3* | osf4* | osf5*) + lt_prog_compiler_wl='-Wl,' + # All OSF/1 code is PIC. + lt_prog_compiler_static='-non_shared' + ;; + + rdos*) + lt_prog_compiler_static='-non_shared' + ;; + + solaris*) + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + case $cc_basename in + f77* | f90* | f95*) + lt_prog_compiler_wl='-Qoption ld ';; + *) + lt_prog_compiler_wl='-Wl,';; + esac + ;; + + sunos4*) + lt_prog_compiler_wl='-Qoption ld ' + lt_prog_compiler_pic='-PIC' + lt_prog_compiler_static='-Bstatic' + ;; + + sysv4 | sysv4.2uw2* | sysv4.3*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + ;; + + sysv4*MP*) + if test -d /usr/nec ;then + lt_prog_compiler_pic='-Kconform_pic' + lt_prog_compiler_static='-Bstatic' + fi + ;; + + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + ;; + + unicos*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_can_build_shared=no + ;; + + uts4*) + lt_prog_compiler_pic='-pic' + lt_prog_compiler_static='-Bstatic' + ;; + + *) + lt_prog_compiler_can_build_shared=no + ;; + esac + fi + +{ echo "$as_me:$LINENO: result: $lt_prog_compiler_pic" >&5 +echo "${ECHO_T}$lt_prog_compiler_pic" >&6; } + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$lt_prog_compiler_pic"; then + +{ echo "$as_me:$LINENO: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5 +echo $ECHO_N "checking if $compiler PIC flag $lt_prog_compiler_pic works... $ECHO_C" >&6; } +if test "${lt_cv_prog_compiler_pic_works+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_cv_prog_compiler_pic_works=no + ac_outfile=conftest.$ac_objext + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$lt_prog_compiler_pic -DPIC" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:7868: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:7872: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_pic_works=yes + fi + fi + $rm conftest* + +fi +{ echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_pic_works" >&5 +echo "${ECHO_T}$lt_cv_prog_compiler_pic_works" >&6; } + +if test x"$lt_cv_prog_compiler_pic_works" = xyes; then + case $lt_prog_compiler_pic in + "" | " "*) ;; + *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;; + esac +else + lt_prog_compiler_pic= + lt_prog_compiler_can_build_shared=no +fi + +fi +case $host_os in + # For platforms which do not support PIC, -DPIC is meaningless: + *djgpp*) + lt_prog_compiler_pic= + ;; + *) + lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC" + ;; +esac + +# +# Check to make sure the static flag actually works. +# +wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\" +{ echo "$as_me:$LINENO: checking if $compiler static flag $lt_tmp_static_flag works" >&5 +echo $ECHO_N "checking if $compiler static flag $lt_tmp_static_flag works... $ECHO_C" >&6; } +if test "${lt_cv_prog_compiler_static_works+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_cv_prog_compiler_static_works=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $lt_tmp_static_flag" + echo "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&5 + $echo "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_static_works=yes + fi + else + lt_cv_prog_compiler_static_works=yes + fi + fi + $rm -r conftest* + LDFLAGS="$save_LDFLAGS" + +fi +{ echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_static_works" >&5 +echo "${ECHO_T}$lt_cv_prog_compiler_static_works" >&6; } + +if test x"$lt_cv_prog_compiler_static_works" = xyes; then + : +else + lt_prog_compiler_static= +fi + + +{ echo "$as_me:$LINENO: checking if $compiler supports -c -o file.$ac_objext" >&5 +echo $ECHO_N "checking if $compiler supports -c -o file.$ac_objext... $ECHO_C" >&6; } +if test "${lt_cv_prog_compiler_c_o+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_cv_prog_compiler_c_o=no + $rm -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:7972: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:7976: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + lt_cv_prog_compiler_c_o=yes + fi + fi + chmod u+w . 2>&5 + $rm conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $rm out/ii_files/* && rmdir out/ii_files + $rm out/* && rmdir out + cd .. + rmdir conftest + $rm conftest* + +fi +{ echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_c_o" >&5 +echo "${ECHO_T}$lt_cv_prog_compiler_c_o" >&6; } + + +hard_links="nottested" +if test "$lt_cv_prog_compiler_c_o" = no && test "$need_locks" != no; then + # do not overwrite the value of need_locks provided by the user + { echo "$as_me:$LINENO: checking if we can lock with hard links" >&5 +echo $ECHO_N "checking if we can lock with hard links... $ECHO_C" >&6; } + hard_links=yes + $rm conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + { echo "$as_me:$LINENO: result: $hard_links" >&5 +echo "${ECHO_T}$hard_links" >&6; } + if test "$hard_links" = no; then + { echo "$as_me:$LINENO: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 +echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} + need_locks=warn + fi +else + need_locks=no +fi + +{ echo "$as_me:$LINENO: checking whether the $compiler linker ($LD) supports shared libraries" >&5 +echo $ECHO_N "checking whether the $compiler linker ($LD) supports shared libraries... $ECHO_C" >&6; } + + runpath_var= + allow_undefined_flag= + enable_shared_with_static_runtimes=no + archive_cmds= + archive_expsym_cmds= + old_archive_From_new_cmds= + old_archive_from_expsyms_cmds= + export_dynamic_flag_spec= + whole_archive_flag_spec= + thread_safe_flag_spec= + hardcode_libdir_flag_spec= + hardcode_libdir_flag_spec_ld= + hardcode_libdir_separator= + hardcode_direct=no + hardcode_minus_L=no + hardcode_shlibpath_var=unsupported + link_all_deplibs=unknown + hardcode_automatic=no + module_cmds= + module_expsym_cmds= + always_export_symbols=no + export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + # include_expsyms should be a list of space-separated symbols to be *always* + # included in the symbol list + include_expsyms= + # exclude_expsyms can be an extended regexp of symbols to exclude + # it will be wrapped by ` (' and `)$', so one must not match beginning or + # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', + # as well as any symbol that contains `d'. + exclude_expsyms='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*' + # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out + # platforms (ab)use it in PIC code, but their linkers get confused if + # the symbol is explicitly referenced. Since portable code cannot + # rely on this symbol name, it's probably fine to never include it in + # preloaded symbol tables. + # Exclude shared library initialization/finalization symbols. + extract_expsyms_cmds= + # Just being paranoid about ensuring that cc_basename is set. + for cc_temp in $compiler""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`$echo "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"` + + case $host_os in + cygwin* | mingw* | pw32*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test "$GCC" != yes; then + with_gnu_ld=no + fi + ;; + interix*) + # we just hope/assume this is gcc and not c89 (= MSVC++) + with_gnu_ld=yes + ;; + openbsd*) + with_gnu_ld=no + ;; + esac + + ld_shlibs=yes + if test "$with_gnu_ld" = yes; then + # If archive_cmds runs LD, not CC, wlarc should be empty + wlarc='${wl}' + + # Set some defaults for GNU ld with shared library support. These + # are reset later if shared libraries are not supported. Putting them + # here allows them to be overridden if necessary. + runpath_var=LD_RUN_PATH + hardcode_libdir_flag_spec='${wl}--rpath ${wl}$libdir' + export_dynamic_flag_spec='${wl}--export-dynamic' + # ancient GNU ld didn't support --whole-archive et. al. + if $LD --help 2>&1 | grep 'no-whole-archive' > /dev/null; then + whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + whole_archive_flag_spec= + fi + supports_anon_versioning=no + case `$LD -v 2>/dev/null` in + *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11 + *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... + *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... + *\ 2.11.*) ;; # other 2.11 versions + *) supports_anon_versioning=yes ;; + esac + + # See if GNU ld supports shared libraries. + case $host_os in + aix[3-9]*) + # On AIX/PPC, the GNU linker is very broken + if test "$host_cpu" != ia64; then + ld_shlibs=no + cat <&2 + +*** Warning: the GNU linker, at least up to release 2.9.1, is reported +*** to be unable to reliably create shared libraries on AIX. +*** Therefore, libtool is disabling shared libraries support. If you +*** really care for shared libraries, you may want to modify your PATH +*** so that a non-GNU linker is found, and then restart. + +EOF + fi + ;; + + amigaos*) + archive_cmds='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + + # Samuel A. Falvo II reports + # that the semantics of dynamic libraries on AmigaOS, at least up + # to version 4, is to share data among multiple programs linked + # with the same dynamic library. Since this doesn't match the + # behavior of shared libraries on other platforms, we can't use + # them. + ld_shlibs=no + ;; + + beos*) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + allow_undefined_flag=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + ld_shlibs=no + fi + ;; + + cygwin* | mingw* | pw32*) + # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless, + # as there is no search path for DLLs. + hardcode_libdir_flag_spec='-L$libdir' + allow_undefined_flag=unsupported + always_export_symbols=no + enable_shared_with_static_runtimes=yes + export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/'\'' -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols' + + if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + ld_shlibs=no + fi + ;; + + interix[3-9]*) + hardcode_direct=no + hardcode_shlibpath_var=no + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + export_dynamic_flag_spec='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + archive_expsym_cmds='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + + gnu* | linux* | k*bsd*-gnu) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + tmp_addflag= + case $cc_basename,$host_cpu in + pgcc*) # Portland Group C compiler + whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag' + ;; + pgf77* | pgf90* | pgf95*) # Portland Group f77 and f90 compilers + whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag -Mnomain' ;; + ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 + tmp_addflag=' -i_dynamic' ;; + efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 + tmp_addflag=' -i_dynamic -nofor_main' ;; + ifc* | ifort*) # Intel Fortran compiler + tmp_addflag=' -nofor_main' ;; + esac + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) # Sun C 5.9 + whole_archive_flag_spec='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_sharedflag='-G' ;; + *Sun\ F*) # Sun Fortran 8.3 + tmp_sharedflag='-G' ;; + *) + tmp_sharedflag='-shared' ;; + esac + archive_cmds='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + + if test $supports_anon_versioning = yes; then + archive_expsym_cmds='$echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + $echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' + fi + else + ld_shlibs=no + fi + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' + wlarc= + else + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + fi + ;; + + solaris*) + if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then + ld_shlibs=no + cat <&2 + +*** Warning: The releases 2.8.* of the GNU linker cannot reliably +*** create shared libraries on Solaris systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.9.1 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +EOF + elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) + case `$LD -v 2>&1` in + *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) + ld_shlibs=no + cat <<_LT_EOF 1>&2 + +*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not +*** reliably create shared libraries on SCO systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.16.91.0.3 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + ;; + *) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + hardcode_libdir_flag_spec='`test -z "$SCOABSPATH" && echo ${wl}-rpath,$libdir`' + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname,\${SCOABSPATH:+${install_libdir}/}$soname,-retain-symbols-file,$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + esac + ;; + + sunos4*) + archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' + wlarc= + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + *) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + esac + + if test "$ld_shlibs" = no; then + runpath_var= + hardcode_libdir_flag_spec= + export_dynamic_flag_spec= + whole_archive_flag_spec= + fi + else + # PORTME fill in a description of your system's linker (not GNU ld) + case $host_os in + aix3*) + allow_undefined_flag=unsupported + always_export_symbols=yes + archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + hardcode_minus_L=yes + if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + hardcode_direct=unsupported + fi + ;; + + aix[4-9]*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + if $NM -V 2>&1 | grep 'GNU' > /dev/null; then + export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols' + else + export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols' + fi + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) + for ld_flag in $LDFLAGS; do + if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then + aix_use_runtimelinking=yes + break + fi + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + archive_cmds='' + hardcode_direct=yes + hardcode_libdir_separator=':' + link_all_deplibs=yes + + if test "$GCC" = yes; then + case $host_os in aix4.[012]|aix4.[012].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && \ + strings "$collect2name" | grep resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + hardcode_direct=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + hardcode_minus_L=yes + hardcode_libdir_flag_spec='-L$libdir' + hardcode_libdir_separator= + fi + ;; + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to export. + always_export_symbols=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + allow_undefined_flag='-berok' + # Determine the default libpath from the value encoded in an empty executable. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + +lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\(.*\)$/\1/ + p + } + }' +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then + aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +fi +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + + hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" + archive_expsym_cmds="\$CC"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib' + allow_undefined_flag="-z nodefs" + archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an empty executable. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + +lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\(.*\)$/\1/ + p + } + }' +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then + aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +fi +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + + hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + no_undefined_flag=' ${wl}-bernotok' + allow_undefined_flag=' ${wl}-berok' + # Exported symbols can be pulled into shared objects from archives + whole_archive_flag_spec='$convenience' + archive_cmds_need_lc=yes + # This is similar to how AIX traditionally builds its shared libraries. + archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + amigaos*) + archive_cmds='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + # see comment about different semantics on the GNU ld section + ld_shlibs=no + ;; + + bsdi[45]*) + export_dynamic_flag_spec=-rdynamic + ;; + + cygwin* | mingw* | pw32*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + hardcode_libdir_flag_spec=' ' + allow_undefined_flag=unsupported + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + archive_cmds='$CC -o $lib $libobjs $compiler_flags `echo "$deplibs" | $SED -e '\''s/ -lc$//'\''` -link -dll~linknames=' + # The linker will automatically build a .lib file if we build a DLL. + old_archive_From_new_cmds='true' + # FIXME: Should let the user specify the lib program. + old_archive_cmds='lib -OUT:$oldlib$oldobjs$old_deplibs' + fix_srcfile_path='`cygpath -w "$srcfile"`' + enable_shared_with_static_runtimes=yes + ;; + + darwin* | rhapsody*) + case $host_os in + rhapsody* | darwin1.[012]) + allow_undefined_flag='${wl}-undefined ${wl}suppress' + ;; + *) # Darwin 1.3 on + if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then + allow_undefined_flag='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' + else + case ${MACOSX_DEPLOYMENT_TARGET} in + 10.[012]) + allow_undefined_flag='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' + ;; + 10.*) + allow_undefined_flag='${wl}-undefined ${wl}dynamic_lookup' + ;; + esac + fi + ;; + esac + archive_cmds_need_lc=no + hardcode_direct=no + hardcode_automatic=yes + hardcode_shlibpath_var=unsupported + whole_archive_flag_spec='' + link_all_deplibs=yes + if test "$GCC" = yes ; then + output_verbose_link_cmd='echo' + archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" + module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" + archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" + module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" + else + case $cc_basename in + xlc*) + output_verbose_link_cmd='echo' + archive_cmds='$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}`echo $rpath/$soname` $xlcverstring' + module_cmds='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' + # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds + archive_expsym_cmds='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}$rpath/$soname $xlcverstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + module_expsym_cmds='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + ;; + *) + ld_shlibs=no + ;; + esac + fi + ;; + + dgux*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_shlibpath_var=no + ;; + + freebsd1*) + ld_shlibs=no + ;; + + # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor + # support. Future versions do this automatically, but an explicit c++rt0.o + # does not break anything, and helps significantly (at the cost of a little + # extra space). + freebsd2.2*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + # Unfortunately, older versions of FreeBSD 2 do not have this feature. + freebsd2*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes + hardcode_minus_L=yes + hardcode_shlibpath_var=no + ;; + + # FreeBSD 3 and greater uses gcc -shared to do shared libraries. + freebsd* | dragonfly*) + archive_cmds='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + hpux9*) + if test "$GCC" = yes; then + archive_cmds='$rm $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + archive_cmds='$rm $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + fi + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + hardcode_direct=yes + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + export_dynamic_flag_spec='${wl}-E' + ;; + + hpux10*) + if test "$GCC" = yes -a "$with_gnu_ld" = no; then + archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' + fi + if test "$with_gnu_ld" = no; then + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + + hardcode_direct=yes + export_dynamic_flag_spec='${wl}-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + fi + ;; + + hpux11*) + if test "$GCC" = yes -a "$with_gnu_ld" = no; then + case $host_cpu in + hppa*64*) + archive_cmds='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + archive_cmds='$CC -shared ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + else + case $host_cpu in + hppa*64*) + archive_cmds='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + fi + if test "$with_gnu_ld" = no; then + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + + case $host_cpu in + hppa*64*|ia64*) + hardcode_libdir_flag_spec_ld='+b $libdir' + hardcode_direct=no + hardcode_shlibpath_var=no + ;; + *) + hardcode_direct=yes + export_dynamic_flag_spec='${wl}-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + ;; + esac + fi + ;; + + irix5* | irix6* | nonstopux*) + if test "$GCC" = yes; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + hardcode_libdir_flag_spec_ld='-rpath $libdir' + fi + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + link_all_deplibs=yes + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out + else + archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF + fi + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + newsos6) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + hardcode_shlibpath_var=no + ;; + + openbsd*) + if test -f /usr/libexec/ld.so; then + hardcode_direct=yes + hardcode_shlibpath_var=no + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + export_dynamic_flag_spec='${wl}-E' + else + case $host_os in + openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-R$libdir' + ;; + *) + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + ;; + esac + fi + else + ld_shlibs=no + fi + ;; + + os2*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + allow_undefined_flag=unsupported + archive_cmds='$echo "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$echo DATA >> $output_objdir/$libname.def~$echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~$echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' + old_archive_From_new_cmds='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' + ;; + + osf3*) + if test "$GCC" = yes; then + allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + allow_undefined_flag=' -expect_unresolved \*' + archive_cmds='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + fi + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + ;; + + osf4* | osf5*) # as osf3* with the addition of -msym flag + if test "$GCC" = yes; then + allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + else + allow_undefined_flag=' -expect_unresolved \*' + archive_cmds='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; echo "-hidden">> $lib.exp~ + $LD -shared${allow_undefined_flag} -input $lib.exp $linker_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib~$rm $lib.exp' + + # Both c and cxx compiler support -rpath directly + hardcode_libdir_flag_spec='-rpath $libdir' + fi + hardcode_libdir_separator=: + ;; + + solaris*) + no_undefined_flag=' -z text' + if test "$GCC" = yes; then + wlarc='${wl}' + archive_cmds='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -shared ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$rm $lib.exp' + else + wlarc='' + archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' + archive_expsym_cmds='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp' + fi + hardcode_libdir_flag_spec='-R$libdir' + hardcode_shlibpath_var=no + case $host_os in + solaris2.[0-5] | solaris2.[0-5].*) ;; + *) + # The compiler driver will combine and reorder linker options, + # but understands `-z linker_flag'. GCC discards it without `$wl', + # but is careful enough not to reorder. + # Supported since Solaris 2.6 (maybe 2.5.1?) + if test "$GCC" = yes; then + whole_archive_flag_spec='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' + else + whole_archive_flag_spec='-z allextract$convenience -z defaultextract' + fi + ;; + esac + link_all_deplibs=yes + ;; + + sunos4*) + if test "x$host_vendor" = xsequent; then + # Use $CC to link under sequent, because it throws in some extra .o + # files that make .init and .fini sections work. + archive_cmds='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' + fi + hardcode_libdir_flag_spec='-L$libdir' + hardcode_direct=yes + hardcode_minus_L=yes + hardcode_shlibpath_var=no + ;; + + sysv4) + case $host_vendor in + sni) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes # is this really true??? + ;; + siemens) + ## LD is ld it makes a PLAMLIB + ## CC just makes a GrossModule. + archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags' + reload_cmds='$CC -r -o $output$reload_objs' + hardcode_direct=no + ;; + motorola) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=no #Motorola manual says yes, but my tests say they lie + ;; + esac + runpath_var='LD_RUN_PATH' + hardcode_shlibpath_var=no + ;; + + sysv4.3*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var=no + export_dynamic_flag_spec='-Bexport' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + ld_shlibs=yes + fi + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) + no_undefined_flag='${wl}-z,text' + archive_cmds_need_lc=no + hardcode_shlibpath_var=no + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + no_undefined_flag='${wl}-z,text' + allow_undefined_flag='${wl}-z,nodefs' + archive_cmds_need_lc=no + hardcode_shlibpath_var=no + hardcode_libdir_flag_spec='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`' + hardcode_libdir_separator=':' + link_all_deplibs=yes + export_dynamic_flag_spec='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + archive_cmds='$CC -shared ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$CC -G ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + uts4*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_shlibpath_var=no + ;; + + *) + ld_shlibs=no + ;; + esac + fi + +{ echo "$as_me:$LINENO: result: $ld_shlibs" >&5 +echo "${ECHO_T}$ld_shlibs" >&6; } +test "$ld_shlibs" = no && can_build_shared=no + +# +# Do we need to explicitly link libc? +# +case "x$archive_cmds_need_lc" in +x|xyes) + # Assume -lc should be added + archive_cmds_need_lc=yes + + if test "$enable_shared" = yes && test "$GCC" = yes; then + case $archive_cmds in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + { echo "$as_me:$LINENO: checking whether -lc should be explicitly linked in" >&5 +echo $ECHO_N "checking whether -lc should be explicitly linked in... $ECHO_C" >&6; } + $rm conftest* + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$lt_prog_compiler_wl + pic_flag=$lt_prog_compiler_pic + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$allow_undefined_flag + allow_undefined_flag= + if { (eval echo "$as_me:$LINENO: \"$archive_cmds 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1\"") >&5 + (eval $archive_cmds 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + then + archive_cmds_need_lc=no + else + archive_cmds_need_lc=yes + fi + allow_undefined_flag=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $rm conftest* + { echo "$as_me:$LINENO: result: $archive_cmds_need_lc" >&5 +echo "${ECHO_T}$archive_cmds_need_lc" >&6; } + ;; + esac + fi + ;; +esac + +{ echo "$as_me:$LINENO: checking dynamic linker characteristics" >&5 +echo $ECHO_N "checking dynamic linker characteristics... $ECHO_C" >&6; } +library_names_spec= +libname_spec='lib$name' +soname_spec= +shrext_cmds=".so" +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" + +if test "$GCC" = yes; then + case $host_os in + darwin*) lt_awk_arg="/^libraries:/,/LR/" ;; + *) lt_awk_arg="/^libraries:/" ;; + esac + lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if echo "$lt_search_path_spec" | grep ';' >/dev/null ; then + # if the path contains ";" then we assume it to be the separator + # otherwise default to the standard path separator (i.e. ":") - it is + # assumed that no part of a normal pathname contains ";" but that should + # okay in the real world where ";" in dirpaths is itself problematic. + lt_search_path_spec=`echo "$lt_search_path_spec" | $SED -e 's/;/ /g'` + else + lt_search_path_spec=`echo "$lt_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + # Ok, now we have the path, separated by spaces, we can step through it + # and add multilib dir if necessary. + lt_tmp_lt_search_path_spec= + lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` + for lt_sys_path in $lt_search_path_spec; do + if test -d "$lt_sys_path/$lt_multi_os_dir"; then + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir" + else + test -d "$lt_sys_path" && \ + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" + fi + done + lt_search_path_spec=`echo $lt_tmp_lt_search_path_spec | awk ' +BEGIN {RS=" "; FS="/|\n";} { + lt_foo=""; + lt_count=0; + for (lt_i = NF; lt_i > 0; lt_i--) { + if ($lt_i != "" && $lt_i != ".") { + if ($lt_i == "..") { + lt_count++; + } else { + if (lt_count == 0) { + lt_foo="/" $lt_i lt_foo; + } else { + lt_count--; + } + } + } + } + if (lt_foo != "") { lt_freq[lt_foo]++; } + if (lt_freq[lt_foo] == 1) { print lt_foo; } +}'` + sys_lib_search_path_spec=`echo $lt_search_path_spec` +else + sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" +fi +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + +case $host_os in +aix3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='${libname}${release}${shared_ext}$major' + ;; + +aix[4-9]*) + version_type=linux + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test "$host_cpu" = ia64; then + # AIX 5 supports IA64 + library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line `#! .'. This would cause the generated library to + # depend on `.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[01] | aix4.[01].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # AIX (on Power*) has no versioning support, so currently we can not hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + if test "$aix_use_runtimelinking" = yes; then + # If using run time linking (on AIX 4.2 or later) use lib.so + # instead of lib.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + else + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='${libname}${release}.a $libname.a' + soname_spec='${libname}${release}${shared_ext}$major' + fi + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' + ;; + +beos*) + library_names_spec='${libname}${shared_ext}' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi[45]*) + version_type=linux + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32*) + version_type=windows + shrext_cmds=".dll" + need_version=no + need_lib_prefix=no + + case $GCC,$host_os in + yes,cygwin* | yes,mingw* | yes,pw32*) + library_names_spec='$libname.dll.a' + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i;echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $rm \$dlpath' + shlibpath_overrides_runpath=yes + + case $host_os in + cygwin*) + # Cygwin DLLs use 'cyg' prefix rather than 'lib' + soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib" + ;; + mingw*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if echo "$sys_lib_search_path_spec" | grep ';[c-zC-Z]:/' >/dev/null; then + # It is most probably a Windows format PATH printed by + # mingw gcc, but we are running on Cygwin. Gcc prints its search + # path with ; separators, and with drive letters. We can handle the + # drive letters (cygwin fileutils understands them), so leave them, + # especially as we might pass files found there to a mingw objdump, + # which wouldn't understand a cygwinified path. Ahh. + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + ;; + pw32*) + # pw32 DLLs use 'pw' prefix rather than 'lib' + library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + ;; + esac + ;; + + *) + library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' + ;; + esac + dynamic_linker='Win32 ld.exe' + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${versuffix}$shared_ext ${libname}${release}${major}$shared_ext ${libname}$shared_ext' + soname_spec='${libname}${release}${major}$shared_ext' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' + + sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib" + sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd1*) + dynamic_linker=no + ;; + +freebsd* | dragonfly*) + # DragonFly does not have aout. When/if they implement a new + # versioning mechanism, adjust this. + if test -x /usr/bin/objformat; then + objformat=`/usr/bin/objformat` + else + case $host_os in + freebsd[123]*) objformat=aout ;; + *) objformat=elf ;; + esac + fi + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[01]* | freebsdelf3.[01]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ + freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + *) # from 4.6 on, and DragonFly + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + esac + ;; + +gnu*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + case $host_cpu in + ia64*) + shrext_cmds='.so' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + if test "X$HPUX_IA64_MODE" = X32; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + fi + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + hppa*64*) + shrext_cmds='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) + shrext_cmds='.sl' + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + ;; + esac + # HP-UX runs *really* slowly unless shared libraries are mode 555. + postinstall_cmds='chmod 555 $lib' + ;; + +interix[3-9]*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) + if test "$lt_cv_prog_gnu_ld" = yes; then + version_type=linux + else + version_type=irix + fi ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") + libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") + libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") + libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" + sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" + hardcode_into_libs=yes + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +# This must be Linux ELF. +linux* | k*bsd*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # Append ld.so.conf contents to the search path + if test -f /etc/ld.so.conf; then + lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '` + sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" + fi + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +nto-qnx*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +openbsd*) + version_type=sunos + sys_lib_dlsearch_path_spec="/usr/lib" + need_lib_prefix=no + # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. + case $host_os in + openbsd3.3 | openbsd3.3.*) need_version=yes ;; + *) need_version=no ;; + esac + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + case $host_os in + openbsd2.[89] | openbsd2.[89].*) + shlibpath_overrides_runpath=no + ;; + *) + shlibpath_overrides_runpath=yes + ;; + esac + else + shlibpath_overrides_runpath=yes + fi + ;; + +os2*) + libname_spec='$name' + shrext_cmds=".dll" + need_lib_prefix=no + library_names_spec='$libname${shared_ext} $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + ;; + +rdos*) + dynamic_linker=no + ;; + +solaris*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + export_dynamic_flag_spec='${wl}-Blargedynsym' + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec ;then + version_type=linux + library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' + soname_spec='$libname${shared_ext}.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + version_type=freebsd-elf + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + if test "$with_gnu_ld" = yes; then + sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' + shlibpath_overrides_runpath=no + else + sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' + shlibpath_overrides_runpath=yes + case $host_os in + sco3.2v5*) + sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" + ;; + esac + fi + sys_lib_dlsearch_path_spec='/usr/lib' + ;; + +uts4*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +{ echo "$as_me:$LINENO: result: $dynamic_linker" >&5 +echo "${ECHO_T}$dynamic_linker" >&6; } +test "$dynamic_linker" = no && can_build_shared=no + +if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_cv_sys_lib_search_path_spec="$sys_lib_search_path_spec" +fi + +sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" +if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_cv_sys_lib_dlsearch_path_spec="$sys_lib_dlsearch_path_spec" +fi + +sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test "$GCC" = yes; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +{ echo "$as_me:$LINENO: checking how to hardcode library paths into programs" >&5 +echo $ECHO_N "checking how to hardcode library paths into programs... $ECHO_C" >&6; } +hardcode_action= +if test -n "$hardcode_libdir_flag_spec" || \ + test -n "$runpath_var" || \ + test "X$hardcode_automatic" = "Xyes" ; then + + # We can hardcode non-existant directories. + if test "$hardcode_direct" != no && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test "$_LT_AC_TAGVAR(hardcode_shlibpath_var, )" != no && + test "$hardcode_minus_L" != no; then + # Linking always hardcodes the temporary library directory. + hardcode_action=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + hardcode_action=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + hardcode_action=unsupported +fi +{ echo "$as_me:$LINENO: result: $hardcode_action" >&5 +echo "${ECHO_T}$hardcode_action" >&6; } + +if test "$hardcode_action" = relink; then + # Fast installation is not supported + enable_fast_install=no +elif test "$shlibpath_overrides_runpath" = yes || + test "$enable_shared" = no; then + # Fast installation is not necessary + enable_fast_install=needless +fi + +striplib= +old_striplib= +{ echo "$as_me:$LINENO: checking whether stripping libraries is possible" >&5 +echo $ECHO_N "checking whether stripping libraries is possible... $ECHO_C" >&6; } +if test -n "$STRIP" && $STRIP -V 2>&1 | grep "GNU strip" >/dev/null; then + test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" + test -z "$striplib" && striplib="$STRIP --strip-unneeded" + { echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } +else +# FIXME - insert some real tests, host_os isn't really good enough + case $host_os in + darwin*) + if test -n "$STRIP" ; then + striplib="$STRIP -x" + old_striplib="$STRIP -S" + { echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } + else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + ;; + *) + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } + ;; + esac +fi + +if test "x$enable_dlopen" != xyes; then + enable_dlopen=unknown + enable_dlopen_self=unknown + enable_dlopen_self_static=unknown +else + lt_cv_dlopen=no + lt_cv_dlopen_libs= + + case $host_os in + beos*) + lt_cv_dlopen="load_add_on" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ;; + + mingw* | pw32*) + lt_cv_dlopen="LoadLibrary" + lt_cv_dlopen_libs= + ;; + + cygwin*) + lt_cv_dlopen="dlopen" + lt_cv_dlopen_libs= + ;; + + darwin*) + # if libdl is installed we need to link against it + { echo "$as_me:$LINENO: checking for dlopen in -ldl" >&5 +echo $ECHO_N "checking for dlopen in -ldl... $ECHO_C" >&6; } +if test "${ac_cv_lib_dl_dlopen+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldl $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* 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 dlopen (); +int +main () +{ +return dlopen (); + ; + return 0; +} +_ACEOF +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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + ac_cv_lib_dl_dlopen=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_lib_dl_dlopen=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ echo "$as_me:$LINENO: result: $ac_cv_lib_dl_dlopen" >&5 +echo "${ECHO_T}$ac_cv_lib_dl_dlopen" >&6; } +if test $ac_cv_lib_dl_dlopen = yes; then + lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" +else + + lt_cv_dlopen="dyld" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + +fi + + ;; + + *) + { echo "$as_me:$LINENO: checking for shl_load" >&5 +echo $ECHO_N "checking for shl_load... $ECHO_C" >&6; } +if test "${ac_cv_func_shl_load+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define shl_load to an innocuous variant, in case declares shl_load. + For example, HP-UX 11i declares gettimeofday. */ +#define shl_load innocuous_shl_load + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char shl_load (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef shl_load + +/* 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 shl_load (); +/* 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_shl_load || defined __stub___shl_load +choke me +#endif + +int +main () +{ +return shl_load (); + ; + return 0; +} +_ACEOF +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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + ac_cv_func_shl_load=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_func_shl_load=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ac_cv_func_shl_load" >&5 +echo "${ECHO_T}$ac_cv_func_shl_load" >&6; } +if test $ac_cv_func_shl_load = yes; then + lt_cv_dlopen="shl_load" +else + { echo "$as_me:$LINENO: checking for shl_load in -ldld" >&5 +echo $ECHO_N "checking for shl_load in -ldld... $ECHO_C" >&6; } +if test "${ac_cv_lib_dld_shl_load+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldld $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* 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 shl_load (); +int +main () +{ +return shl_load (); + ; + return 0; +} +_ACEOF +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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + ac_cv_lib_dld_shl_load=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_lib_dld_shl_load=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ echo "$as_me:$LINENO: result: $ac_cv_lib_dld_shl_load" >&5 +echo "${ECHO_T}$ac_cv_lib_dld_shl_load" >&6; } +if test $ac_cv_lib_dld_shl_load = yes; then + lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld" +else + { echo "$as_me:$LINENO: checking for dlopen" >&5 +echo $ECHO_N "checking for dlopen... $ECHO_C" >&6; } +if test "${ac_cv_func_dlopen+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define dlopen to an innocuous variant, in case declares dlopen. + For example, HP-UX 11i declares gettimeofday. */ +#define dlopen innocuous_dlopen + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char dlopen (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef dlopen + +/* 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 dlopen (); +/* 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_dlopen || defined __stub___dlopen +choke me +#endif + +int +main () +{ +return dlopen (); + ; + return 0; +} +_ACEOF +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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + ac_cv_func_dlopen=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_func_dlopen=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ac_cv_func_dlopen" >&5 +echo "${ECHO_T}$ac_cv_func_dlopen" >&6; } +if test $ac_cv_func_dlopen = yes; then + lt_cv_dlopen="dlopen" +else + { echo "$as_me:$LINENO: checking for dlopen in -ldl" >&5 +echo $ECHO_N "checking for dlopen in -ldl... $ECHO_C" >&6; } +if test "${ac_cv_lib_dl_dlopen+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldl $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* 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 dlopen (); +int +main () +{ +return dlopen (); + ; + return 0; +} +_ACEOF +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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + ac_cv_lib_dl_dlopen=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_lib_dl_dlopen=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ echo "$as_me:$LINENO: result: $ac_cv_lib_dl_dlopen" >&5 +echo "${ECHO_T}$ac_cv_lib_dl_dlopen" >&6; } +if test $ac_cv_lib_dl_dlopen = yes; then + lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" +else + { echo "$as_me:$LINENO: checking for dlopen in -lsvld" >&5 +echo $ECHO_N "checking for dlopen in -lsvld... $ECHO_C" >&6; } +if test "${ac_cv_lib_svld_dlopen+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsvld $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* 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 dlopen (); +int +main () +{ +return dlopen (); + ; + return 0; +} +_ACEOF +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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + ac_cv_lib_svld_dlopen=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_lib_svld_dlopen=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ echo "$as_me:$LINENO: result: $ac_cv_lib_svld_dlopen" >&5 +echo "${ECHO_T}$ac_cv_lib_svld_dlopen" >&6; } +if test $ac_cv_lib_svld_dlopen = yes; then + lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld" +else + { echo "$as_me:$LINENO: checking for dld_link in -ldld" >&5 +echo $ECHO_N "checking for dld_link in -ldld... $ECHO_C" >&6; } +if test "${ac_cv_lib_dld_dld_link+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldld $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* 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 dld_link (); +int +main () +{ +return dld_link (); + ; + return 0; +} +_ACEOF +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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + ac_cv_lib_dld_dld_link=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_lib_dld_dld_link=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ echo "$as_me:$LINENO: result: $ac_cv_lib_dld_dld_link" >&5 +echo "${ECHO_T}$ac_cv_lib_dld_dld_link" >&6; } +if test $ac_cv_lib_dld_dld_link = yes; then + lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld" +fi + + +fi + + +fi + + +fi + + +fi + + +fi + + ;; + esac + + if test "x$lt_cv_dlopen" != xno; then + enable_dlopen=yes + else + enable_dlopen=no + fi + + case $lt_cv_dlopen in + dlopen) + save_CPPFLAGS="$CPPFLAGS" + test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" + + save_LDFLAGS="$LDFLAGS" + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" + + save_LIBS="$LIBS" + LIBS="$lt_cv_dlopen_libs $LIBS" + + { echo "$as_me:$LINENO: checking whether a program can dlopen itself" >&5 +echo $ECHO_N "checking whether a program can dlopen itself... $ECHO_C" >&6; } +if test "${lt_cv_dlopen_self+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test "$cross_compiling" = yes; then : + lt_cv_dlopen_self=cross +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext < +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +#ifdef __cplusplus +extern "C" void exit (int); +#endif + +void fnord() { int i=42;} +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + /* dlclose (self); */ + } + else + puts (dlerror ()); + + exit (status); +} +EOF + if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) >&5 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;; + x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;; + x$lt_dlunknown|x*) lt_cv_dlopen_self=no ;; + esac + else : + # compilation failed + lt_cv_dlopen_self=no + fi +fi +rm -fr conftest* + + +fi +{ echo "$as_me:$LINENO: result: $lt_cv_dlopen_self" >&5 +echo "${ECHO_T}$lt_cv_dlopen_self" >&6; } + + if test "x$lt_cv_dlopen_self" = xyes; then + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" + { echo "$as_me:$LINENO: checking whether a statically linked program can dlopen itself" >&5 +echo $ECHO_N "checking whether a statically linked program can dlopen itself... $ECHO_C" >&6; } +if test "${lt_cv_dlopen_self_static+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test "$cross_compiling" = yes; then : + lt_cv_dlopen_self_static=cross +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext < +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +#ifdef __cplusplus +extern "C" void exit (int); +#endif + +void fnord() { int i=42;} +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + /* dlclose (self); */ + } + else + puts (dlerror ()); + + exit (status); +} +EOF + if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) >&5 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;; + x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;; + x$lt_dlunknown|x*) lt_cv_dlopen_self_static=no ;; + esac + else : + # compilation failed + lt_cv_dlopen_self_static=no + fi +fi +rm -fr conftest* + + +fi +{ echo "$as_me:$LINENO: result: $lt_cv_dlopen_self_static" >&5 +echo "${ECHO_T}$lt_cv_dlopen_self_static" >&6; } + fi + + CPPFLAGS="$save_CPPFLAGS" + LDFLAGS="$save_LDFLAGS" + LIBS="$save_LIBS" + ;; + esac + + case $lt_cv_dlopen_self in + yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; + *) enable_dlopen_self=unknown ;; + esac + + case $lt_cv_dlopen_self_static in + yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; + *) enable_dlopen_self_static=unknown ;; + esac +fi + + +# Report which library types will actually be built +{ echo "$as_me:$LINENO: checking if libtool supports shared libraries" >&5 +echo $ECHO_N "checking if libtool supports shared libraries... $ECHO_C" >&6; } +{ echo "$as_me:$LINENO: result: $can_build_shared" >&5 +echo "${ECHO_T}$can_build_shared" >&6; } + +{ echo "$as_me:$LINENO: checking whether to build shared libraries" >&5 +echo $ECHO_N "checking whether to build shared libraries... $ECHO_C" >&6; } +test "$can_build_shared" = "no" && enable_shared=no + +# On AIX, shared libraries and static libraries use the same namespace, and +# are all built from PIC. +case $host_os in +aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + +aix[4-9]*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; +esac +{ echo "$as_me:$LINENO: result: $enable_shared" >&5 +echo "${ECHO_T}$enable_shared" >&6; } + +{ echo "$as_me:$LINENO: checking whether to build static libraries" >&5 +echo $ECHO_N "checking whether to build static libraries... $ECHO_C" >&6; } +# Make sure either enable_shared or enable_static is yes. +test "$enable_shared" = yes || enable_static=yes +{ echo "$as_me:$LINENO: result: $enable_static" >&5 +echo "${ECHO_T}$enable_static" >&6; } + +# The else clause should only fire when bootstrapping the +# libtool distribution, otherwise you forgot to ship ltmain.sh +# with your package, and you will get complaints that there are +# no rules to generate ltmain.sh. +if test -f "$ltmain"; then + # See if we are running on zsh, and set the options which allow our commands through + # without removal of \ escapes. + if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST + fi + # Now quote all the things that may contain metacharacters while being + # careful not to overquote the AC_SUBSTed values. We take copies of the + # variables and quote the copies for generation of the libtool script. + for var in echo old_CC old_CFLAGS AR AR_FLAGS EGREP RANLIB LN_S LTCC LTCFLAGS NM \ + SED SHELL STRIP \ + libname_spec library_names_spec soname_spec extract_expsyms_cmds \ + old_striplib striplib file_magic_cmd finish_cmds finish_eval \ + deplibs_check_method reload_flag reload_cmds need_locks \ + lt_cv_sys_global_symbol_pipe lt_cv_sys_global_symbol_to_cdecl \ + lt_cv_sys_global_symbol_to_c_name_address \ + sys_lib_search_path_spec sys_lib_dlsearch_path_spec \ + old_postinstall_cmds old_postuninstall_cmds \ + compiler \ + CC \ + LD \ + lt_prog_compiler_wl \ + lt_prog_compiler_pic \ + lt_prog_compiler_static \ + lt_prog_compiler_no_builtin_flag \ + export_dynamic_flag_spec \ + thread_safe_flag_spec \ + whole_archive_flag_spec \ + enable_shared_with_static_runtimes \ + old_archive_cmds \ + old_archive_from_new_cmds \ + predep_objects \ + postdep_objects \ + predeps \ + postdeps \ + compiler_lib_search_path \ + compiler_lib_search_dirs \ + archive_cmds \ + archive_expsym_cmds \ + postinstall_cmds \ + postuninstall_cmds \ + old_archive_from_expsyms_cmds \ + allow_undefined_flag \ + no_undefined_flag \ + export_symbols_cmds \ + hardcode_libdir_flag_spec \ + hardcode_libdir_flag_spec_ld \ + hardcode_libdir_separator \ + hardcode_automatic \ + module_cmds \ + module_expsym_cmds \ + lt_cv_prog_compiler_c_o \ + fix_srcfile_path \ + exclude_expsyms \ + include_expsyms; do + + case $var in + old_archive_cmds | \ + old_archive_from_new_cmds | \ + archive_cmds | \ + archive_expsym_cmds | \ + module_cmds | \ + module_expsym_cmds | \ + old_archive_from_expsyms_cmds | \ + export_symbols_cmds | \ + extract_expsyms_cmds | reload_cmds | finish_cmds | \ + postinstall_cmds | postuninstall_cmds | \ + old_postinstall_cmds | old_postuninstall_cmds | \ + sys_lib_search_path_spec | sys_lib_dlsearch_path_spec) + # Double-quote double-evaled strings. + eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\"" + ;; + *) + eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\"" + ;; + esac + done + + case $lt_echo in + *'\$0 --fallback-echo"') + lt_echo=`$echo "X$lt_echo" | $Xsed -e 's/\\\\\\\$0 --fallback-echo"$/$0 --fallback-echo"/'` + ;; + esac + +cfgfile="${ofile}T" + trap "$rm \"$cfgfile\"; exit 1" 1 2 15 + $rm -f "$cfgfile" + { echo "$as_me:$LINENO: creating $ofile" >&5 +echo "$as_me: creating $ofile" >&6;} + + cat <<__EOF__ >> "$cfgfile" +#! $SHELL + +# `$echo "$cfgfile" | sed 's%^.*/%%'` - Provide generalized library-building support services. +# Generated automatically by $PROGRAM (GNU $PACKAGE $VERSION$TIMESTAMP) +# NOTE: Changes made to this file will be lost: look at ltmain.sh. +# +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 +# Free Software Foundation, Inc. +# +# This file is part of GNU Libtool: +# Originally by Gordon Matzigkeit , 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 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# 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. + +# A sed program that does not truncate output. +SED=$lt_SED + +# Sed that helps us avoid accidentally triggering echo(1) options like -n. +Xsed="$SED -e 1s/^X//" + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +# The names of the tagged configurations supported by this script. +available_tags= + +# ### BEGIN LIBTOOL CONFIG + +# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: + +# Shell to use when invoking shell scripts. +SHELL=$lt_SHELL + +# Whether or not to build shared libraries. +build_libtool_libs=$enable_shared + +# Whether or not to build static libraries. +build_old_libs=$enable_static + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=$archive_cmds_need_lc + +# Whether or not to disallow shared libs when runtime libs are static +allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes + +# Whether or not to optimize for fast installation. +fast_install=$enable_fast_install + +# The host system. +host_alias=$host_alias +host=$host +host_os=$host_os + +# The build system. +build_alias=$build_alias +build=$build +build_os=$build_os + +# An echo program that does not interpret backslashes. +echo=$lt_echo + +# The archiver. +AR=$lt_AR +AR_FLAGS=$lt_AR_FLAGS + +# A C compiler. +LTCC=$lt_LTCC + +# LTCC compiler flags. +LTCFLAGS=$lt_LTCFLAGS + +# A language-specific compiler. +CC=$lt_compiler + +# Is the compiler the GNU C compiler? +with_gcc=$GCC + +# An ERE matcher. +EGREP=$lt_EGREP + +# The linker used to build libraries. +LD=$lt_LD + +# Whether we need hard or soft links. +LN_S=$lt_LN_S + +# A BSD-compatible nm program. +NM=$lt_NM + +# A symbol stripping program +STRIP=$lt_STRIP + +# Used to examine libraries when file_magic_cmd begins "file" +MAGIC_CMD=$MAGIC_CMD + +# Used on cygwin: DLL creation program. +DLLTOOL="$DLLTOOL" + +# Used on cygwin: object dumper. +OBJDUMP="$OBJDUMP" + +# Used on cygwin: assembler. +AS="$AS" + +# The name of the directory that contains temporary libtool files. +objdir=$objdir + +# How to create reloadable object files. +reload_flag=$lt_reload_flag +reload_cmds=$lt_reload_cmds + +# How to pass a linker flag through the compiler. +wl=$lt_lt_prog_compiler_wl + +# Object file suffix (normally "o"). +objext="$ac_objext" + +# Old archive suffix (normally "a"). +libext="$libext" + +# Shared library suffix (normally ".so"). +shrext_cmds='$shrext_cmds' + +# Executable file suffix (normally ""). +exeext="$exeext" + +# Additional compiler flags for building library objects. +pic_flag=$lt_lt_prog_compiler_pic +pic_mode=$pic_mode + +# What is the maximum length of a command? +max_cmd_len=$lt_cv_sys_max_cmd_len + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$lt_lt_cv_prog_compiler_c_o + +# Must we lock files when doing compilation? +need_locks=$lt_need_locks + +# Do we need the lib prefix for modules? +need_lib_prefix=$need_lib_prefix + +# Do we need a version for libraries? +need_version=$need_version + +# Whether dlopen is supported. +dlopen_support=$enable_dlopen + +# Whether dlopen of programs is supported. +dlopen_self=$enable_dlopen_self + +# Whether dlopen of statically linked programs is supported. +dlopen_self_static=$enable_dlopen_self_static + +# Compiler flag to prevent dynamic linking. +link_static_flag=$lt_lt_prog_compiler_static + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec=$lt_export_dynamic_flag_spec + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec=$lt_whole_archive_flag_spec + +# Compiler flag to generate thread-safe objects. +thread_safe_flag_spec=$lt_thread_safe_flag_spec + +# Library versioning type. +version_type=$version_type + +# Format of library name prefix. +libname_spec=$lt_libname_spec + +# List of archive names. First name is the real one, the rest are links. +# The last name is the one that the linker finds with -lNAME. +library_names_spec=$lt_library_names_spec + +# The coded name of the library, if different from the real name. +soname_spec=$lt_soname_spec + +# Commands used to build and install an old-style archive. +RANLIB=$lt_RANLIB +old_archive_cmds=$lt_old_archive_cmds +old_postinstall_cmds=$lt_old_postinstall_cmds +old_postuninstall_cmds=$lt_old_postuninstall_cmds + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds=$lt_old_archive_from_new_cmds + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds + +# Commands used to build and install a shared archive. +archive_cmds=$lt_archive_cmds +archive_expsym_cmds=$lt_archive_expsym_cmds +postinstall_cmds=$lt_postinstall_cmds +postuninstall_cmds=$lt_postuninstall_cmds + +# Commands used to build a loadable module (assumed same as above if empty) +module_cmds=$lt_module_cmds +module_expsym_cmds=$lt_module_expsym_cmds + +# Commands to strip libraries. +old_striplib=$lt_old_striplib +striplib=$lt_striplib + +# Dependencies to place before the objects being linked to create a +# shared library. +predep_objects=$lt_predep_objects + +# Dependencies to place after the objects being linked to create a +# shared library. +postdep_objects=$lt_postdep_objects + +# Dependencies to place before the objects being linked to create a +# shared library. +predeps=$lt_predeps + +# Dependencies to place after the objects being linked to create a +# shared library. +postdeps=$lt_postdeps + +# The directories searched by this compiler when creating a shared +# library +compiler_lib_search_dirs=$lt_compiler_lib_search_dirs + +# The library search path used internally by the compiler when linking +# a shared library. +compiler_lib_search_path=$lt_compiler_lib_search_path + +# Method to check whether dependent libraries are shared objects. +deplibs_check_method=$lt_deplibs_check_method + +# Command to use when deplibs_check_method == file_magic. +file_magic_cmd=$lt_file_magic_cmd + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$lt_allow_undefined_flag + +# Flag that forces no undefined symbols. +no_undefined_flag=$lt_no_undefined_flag + +# Commands used to finish a libtool library installation in a directory. +finish_cmds=$lt_finish_cmds + +# Same as above, but a single script fragment to be evaled but not shown. +finish_eval=$lt_finish_eval + +# Take the output of nm and produce a listing of raw symbols and C names. +global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe + +# Transform the output of nm in a proper C declaration +global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl + +# Transform the output of nm in a C name address pair +global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address + +# This is the shared library runtime path variable. +runpath_var=$runpath_var + +# This is the shared library path variable. +shlibpath_var=$shlibpath_var + +# Is shlibpath searched before the hard-coded library search path? +shlibpath_overrides_runpath=$shlibpath_overrides_runpath + +# How to hardcode a shared library path into an executable. +hardcode_action=$hardcode_action + +# Whether we should hardcode library paths into libraries. +hardcode_into_libs=$hardcode_into_libs + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist. +hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec + +# If ld is used when linking, flag to hardcode \$libdir into +# a binary during linking. This must work even if \$libdir does +# not exist. +hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld + +# Whether we need a single -rpath flag with a separated argument. +hardcode_libdir_separator=$lt_hardcode_libdir_separator + +# Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the +# resulting binary. +hardcode_direct=$hardcode_direct + +# Set to yes if using the -LDIR flag during linking hardcodes DIR into the +# resulting binary. +hardcode_minus_L=$hardcode_minus_L + +# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into +# the resulting binary. +hardcode_shlibpath_var=$hardcode_shlibpath_var + +# Set to yes if building a shared library automatically hardcodes DIR into the library +# and all subsequent libraries and executables linked against it. +hardcode_automatic=$hardcode_automatic + +# Variables whose values should be saved in libtool wrapper scripts and +# restored at relink time. +variables_saved_for_relink="$variables_saved_for_relink" + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=$link_all_deplibs + +# Compile-time system search path for libraries +sys_lib_search_path_spec=$lt_sys_lib_search_path_spec + +# Run-time system search path for libraries +sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec + +# Fix the shell variable \$srcfile for the compiler. +fix_srcfile_path=$lt_fix_srcfile_path + +# Set to yes if exported symbols are required. +always_export_symbols=$always_export_symbols + +# The commands to list exported symbols. +export_symbols_cmds=$lt_export_symbols_cmds + +# The commands to extract the exported symbol list from a shared archive. +extract_expsyms_cmds=$lt_extract_expsyms_cmds + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms=$lt_exclude_expsyms + +# Symbols that must always be exported. +include_expsyms=$lt_include_expsyms + +# ### END LIBTOOL CONFIG + +__EOF__ + + + case $host_os in + aix3*) + cat <<\EOF >> "$cfgfile" + +# AIX sometimes has problems with the GCC collect2 program. For some +# reason, if we set the COLLECT_NAMES environment variable, the problems +# vanish in a puff of smoke. +if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES +fi +EOF + ;; + esac + + # We use sed instead of cat because bash on DJGPP gets confused if + # if finds mixed CR/LF and LF-only lines. Since sed operates in + # text mode, it properly converts lines to CR/LF. This bash problem + # is reportedly fixed, but why not run on old versions too? + sed '$q' "$ltmain" >> "$cfgfile" || (rm -f "$cfgfile"; exit 1) + + mv -f "$cfgfile" "$ofile" || \ + (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") + chmod +x "$ofile" + +else + # If there is no Makefile yet, we rely on a make rule to execute + # `config.status --recheck' to rerun these tests and create the + # libtool script then. + ltmain_in=`echo $ltmain | sed -e 's/\.sh$/.in/'` + if test -f "$ltmain_in"; then + test -f Makefile && make "$ltmain" + 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 + +CC="$lt_save_CC" + + +# Check whether --with-tags was given. +if test "${with_tags+set}" = set; then + withval=$with_tags; tagnames="$withval" +fi + + +if test -f "$ltmain" && test -n "$tagnames"; then + if test ! -f "${ofile}"; then + { echo "$as_me:$LINENO: WARNING: output file \`$ofile' does not exist" >&5 +echo "$as_me: WARNING: output file \`$ofile' does not exist" >&2;} + fi + + if test -z "$LTCC"; then + eval "`$SHELL ${ofile} --config | grep '^LTCC='`" + if test -z "$LTCC"; then + { echo "$as_me:$LINENO: WARNING: output file \`$ofile' does not look like a libtool script" >&5 +echo "$as_me: WARNING: output file \`$ofile' does not look like a libtool script" >&2;} + else + { echo "$as_me:$LINENO: WARNING: using \`LTCC=$LTCC', extracted from \`$ofile'" >&5 +echo "$as_me: WARNING: using \`LTCC=$LTCC', extracted from \`$ofile'" >&2;} + fi + fi + if test -z "$LTCFLAGS"; then + eval "`$SHELL ${ofile} --config | grep '^LTCFLAGS='`" + fi + + # Extract list of available tagged configurations in $ofile. + # Note that this assumes the entire list is on one line. + available_tags=`grep "^available_tags=" "${ofile}" | $SED -e 's/available_tags=\(.*$\)/\1/' -e 's/\"//g'` + + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for tagname in $tagnames; do + IFS="$lt_save_ifs" + # Check whether tagname contains only valid characters + case `$echo "X$tagname" | $Xsed -e 's:[-_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890,/]::g'` in + "") ;; + *) { { echo "$as_me:$LINENO: error: invalid tag name: $tagname" >&5 +echo "$as_me: error: invalid tag name: $tagname" >&2;} + { (exit 1); exit 1; }; } + ;; + esac + + if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$" < "${ofile}" > /dev/null + then + { { echo "$as_me:$LINENO: error: tag name \"$tagname\" already exists" >&5 +echo "$as_me: error: tag name \"$tagname\" already exists" >&2;} + { (exit 1); exit 1; }; } + fi + + # Update the list of available tags. + if test -n "$tagname"; then + echo appending configuration tag \"$tagname\" to $ofile + + case $tagname in + CXX) + if test -n "$CXX" && ( test "X$CXX" != "Xno" && + ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || + (test "X$CXX" != "Xg++"))) ; then + 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 + + + + +archive_cmds_need_lc_CXX=no +allow_undefined_flag_CXX= +always_export_symbols_CXX=no +archive_expsym_cmds_CXX= +export_dynamic_flag_spec_CXX= +hardcode_direct_CXX=no +hardcode_libdir_flag_spec_CXX= +hardcode_libdir_flag_spec_ld_CXX= +hardcode_libdir_separator_CXX= +hardcode_minus_L_CXX=no +hardcode_shlibpath_var_CXX=unsupported +hardcode_automatic_CXX=no +module_cmds_CXX= +module_expsym_cmds_CXX= +link_all_deplibs_CXX=unknown +old_archive_cmds_CXX=$old_archive_cmds +no_undefined_flag_CXX= +whole_archive_flag_spec_CXX= +enable_shared_with_static_runtimes_CXX=no + +# Dependencies to place before and after the object being linked: +predep_objects_CXX= +postdep_objects_CXX= +predeps_CXX= +postdeps_CXX= +compiler_lib_search_path_CXX= +compiler_lib_search_dirs_CXX= + +# Source file extension for C++ test sources. +ac_ext=cpp + +# Object file extension for compiled C++ test sources. +objext=o +objext_CXX=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="int some_variable = 0;" + +# Code to be used in simple link tests +lt_simple_link_test_code='int main(int, char *[]) { return(0); }' + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC + + +# save warnings/boilerplate of simple test code +ac_outfile=conftest.$ac_objext +echo "$lt_simple_compile_test_code" >conftest.$ac_ext +eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_compiler_boilerplate=`cat conftest.err` +$rm conftest* + +ac_outfile=conftest.$ac_objext +echo "$lt_simple_link_test_code" >conftest.$ac_ext +eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_linker_boilerplate=`cat conftest.err` +$rm -r conftest* + + +# Allow CC to be a program name with arguments. +lt_save_CC=$CC +lt_save_LD=$LD +lt_save_GCC=$GCC +GCC=$GXX +lt_save_with_gnu_ld=$with_gnu_ld +lt_save_path_LD=$lt_cv_path_LD +if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then + lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx +else + $as_unset lt_cv_prog_gnu_ld +fi +if test -n "${lt_cv_path_LDCXX+set}"; then + lt_cv_path_LD=$lt_cv_path_LDCXX +else + $as_unset lt_cv_path_LD +fi +test -z "${LDCXX+set}" || LD=$LDCXX +CC=${CXX-"c++"} +compiler=$CC +compiler_CXX=$CC +for cc_temp in $compiler""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`$echo "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"` + + +# We don't want -fno-exception wen compiling C++ code, so set the +# no_builtin_flag separately +if test "$GXX" = yes; then + lt_prog_compiler_no_builtin_flag_CXX=' -fno-builtin' +else + lt_prog_compiler_no_builtin_flag_CXX= +fi + +if test "$GXX" = yes; then + # Set up default GNU C++ configuration + + +# Check whether --with-gnu-ld was given. +if test "${with_gnu_ld+set}" = set; then + withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes +else + with_gnu_ld=no +fi + +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + { echo "$as_me:$LINENO: checking for ld used by $CC" >&5 +echo $ECHO_N "checking for ld used by $CC... $ECHO_C" >&6; } + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [\\/]* | ?:[\\/]*) + re_direlt='/[^/][^/]*/\.\./' + # Canonicalize the pathname of ld + ac_prog=`echo $ac_prog| $SED 's%\\\\%/%g'` + while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do + ac_prog=`echo $ac_prog| $SED "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + { echo "$as_me:$LINENO: checking for GNU ld" >&5 +echo $ECHO_N "checking for GNU ld... $ECHO_C" >&6; } +else + { echo "$as_me:$LINENO: checking for non-GNU ld" >&5 +echo $ECHO_N "checking for non-GNU ld... $ECHO_C" >&6; } +fi +if test "${lt_cv_path_LD+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -z "$LD"; then + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some variants of GNU ld only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$lt_cv_path_LD" -v 2>&1 &5 +echo "${ECHO_T}$LD" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi +test -z "$LD" && { { echo "$as_me:$LINENO: error: no acceptable ld found in \$PATH" >&5 +echo "$as_me: error: no acceptable ld found in \$PATH" >&2;} + { (exit 1); exit 1; }; } +{ echo "$as_me:$LINENO: checking if the linker ($LD) is GNU ld" >&5 +echo $ECHO_N "checking if the linker ($LD) is GNU ld... $ECHO_C" >&6; } +if test "${lt_cv_prog_gnu_ld+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # I'd rather use --version here, but apparently some GNU lds only accept -v. +case `$LD -v 2>&1 &5 +echo "${ECHO_T}$lt_cv_prog_gnu_ld" >&6; } +with_gnu_ld=$lt_cv_prog_gnu_ld + + + + # Check if GNU C++ uses GNU ld as the underlying linker, since the + # archiving commands below assume that GNU ld is being used. + if test "$with_gnu_ld" = yes; then + archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + + hardcode_libdir_flag_spec_CXX='${wl}--rpath ${wl}$libdir' + export_dynamic_flag_spec_CXX='${wl}--export-dynamic' + + # If archive_cmds runs LD, not CC, wlarc should be empty + # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to + # investigate it a little bit more. (MM) + wlarc='${wl}' + + # ancient GNU ld didn't support --whole-archive et. al. + if eval "`$CC -print-prog-name=ld` --help 2>&1" | \ + grep 'no-whole-archive' > /dev/null; then + whole_archive_flag_spec_CXX="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + whole_archive_flag_spec_CXX= + fi + else + with_gnu_ld=no + wlarc= + + # A generic and very simple default shared library creation + # command for GNU C++ for the case where it uses the native + # linker, instead of GNU ld. If possible, this setting should + # overridden to take advantage of the native linker features on + # the platform it is being used on. + archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + fi + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"' + +else + GXX=no + with_gnu_ld=no + wlarc= +fi + +# PORTME: fill in a description of your system's C++ link characteristics +{ echo "$as_me:$LINENO: checking whether the $compiler linker ($LD) supports shared libraries" >&5 +echo $ECHO_N "checking whether the $compiler linker ($LD) supports shared libraries... $ECHO_C" >&6; } +ld_shlibs_CXX=yes +case $host_os in + aix3*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + aix[4-9]*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) + for ld_flag in $LDFLAGS; do + case $ld_flag in + *-brtl*) + aix_use_runtimelinking=yes + break + ;; + esac + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + archive_cmds_CXX='' + hardcode_direct_CXX=yes + hardcode_libdir_separator_CXX=':' + link_all_deplibs_CXX=yes + + if test "$GXX" = yes; then + case $host_os in aix4.[012]|aix4.[012].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && \ + strings "$collect2name" | grep resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + hardcode_direct_CXX=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + hardcode_minus_L_CXX=yes + hardcode_libdir_flag_spec_CXX='-L$libdir' + hardcode_libdir_separator_CXX= + fi + ;; + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to export. + always_export_symbols_CXX=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + allow_undefined_flag_CXX='-berok' + # Determine the default libpath from the value encoded in an empty executable. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + +lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\(.*\)$/\1/ + p + } + }' +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then + aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +fi +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + + hardcode_libdir_flag_spec_CXX='${wl}-blibpath:$libdir:'"$aix_libpath" + + archive_expsym_cmds_CXX="\$CC"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + hardcode_libdir_flag_spec_CXX='${wl}-R $libdir:/usr/lib:/lib' + allow_undefined_flag_CXX="-z nodefs" + archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an empty executable. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + +lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\(.*\)$/\1/ + p + } + }' +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then + aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +fi +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + + hardcode_libdir_flag_spec_CXX='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + no_undefined_flag_CXX=' ${wl}-bernotok' + allow_undefined_flag_CXX=' ${wl}-berok' + # Exported symbols can be pulled into shared objects from archives + whole_archive_flag_spec_CXX='$convenience' + archive_cmds_need_lc_CXX=yes + # This is similar to how AIX traditionally builds its shared libraries. + archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + beos*) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + allow_undefined_flag_CXX=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + archive_cmds_CXX='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + ld_shlibs_CXX=no + fi + ;; + + chorus*) + case $cc_basename in + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + + cygwin* | mingw* | pw32*) + # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, CXX) is actually meaningless, + # as there is no search path for DLLs. + hardcode_libdir_flag_spec_CXX='-L$libdir' + allow_undefined_flag_CXX=unsupported + always_export_symbols_CXX=no + enable_shared_with_static_runtimes_CXX=yes + + if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then + archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + archive_expsym_cmds_CXX='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + ld_shlibs_CXX=no + fi + ;; + darwin* | rhapsody*) + archive_cmds_need_lc_CXX=no + hardcode_direct_CXX=no + hardcode_automatic_CXX=yes + hardcode_shlibpath_var_CXX=unsupported + whole_archive_flag_spec_CXX='' + link_all_deplibs_CXX=yes + allow_undefined_flag_CXX="$_lt_dar_allow_undefined" + if test "$GXX" = yes ; then + output_verbose_link_cmd='echo' + archive_cmds_CXX="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" + module_cmds_CXX="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" + archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" + module_expsym_cmds_CXX="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" + if test "$lt_cv_apple_cc_single_mod" != "yes"; then + archive_cmds_CXX="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}" + archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}" + fi + else + case $cc_basename in + xlc*) + output_verbose_link_cmd='echo' + archive_cmds_CXX='$CC -qmkshrobj ${wl}-single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}`echo $rpath/$soname` $xlcverstring' + module_cmds_CXX='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' + # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds + archive_expsym_cmds_CXX='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -qmkshrobj ${wl}-single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}$rpath/$soname $xlcverstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + module_expsym_cmds_CXX='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + ;; + *) + ld_shlibs_CXX=no + ;; + esac + fi + ;; + + dgux*) + case $cc_basename in + ec++*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + ghcx*) + # Green Hills C++ Compiler + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + freebsd[12]*) + # C++ shared libraries reported to be fairly broken before switch to ELF + ld_shlibs_CXX=no + ;; + freebsd-elf*) + archive_cmds_need_lc_CXX=no + ;; + freebsd* | dragonfly*) + # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF + # conventions + ld_shlibs_CXX=yes + ;; + gnu*) + ;; + hpux9*) + hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir' + hardcode_libdir_separator_CXX=: + export_dynamic_flag_spec_CXX='${wl}-E' + hardcode_direct_CXX=yes + hardcode_minus_L_CXX=yes # Not in the search PATH, + # but as the default + # location of the library. + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + aCC*) + archive_cmds_CXX='$rm $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | grep "[-]L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + *) + if test "$GXX" = yes; then + archive_cmds_CXX='$rm $output_objdir/$soname~$CC -shared -nostdlib -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + fi + ;; + esac + ;; + hpux10*|hpux11*) + if test $with_gnu_ld = no; then + hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir' + hardcode_libdir_separator_CXX=: + + case $host_cpu in + hppa*64*|ia64*) ;; + *) + export_dynamic_flag_spec_CXX='${wl}-E' + ;; + esac + fi + case $host_cpu in + hppa*64*|ia64*) + hardcode_direct_CXX=no + hardcode_shlibpath_var_CXX=no + ;; + *) + hardcode_direct_CXX=yes + hardcode_minus_L_CXX=yes # Not in the search PATH, + # but as the default + # location of the library. + ;; + esac + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + aCC*) + case $host_cpu in + hppa*64*) + archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | grep "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + *) + if test "$GXX" = yes; then + if test $with_gnu_ld = no; then + case $host_cpu in + hppa*64*) + archive_cmds_CXX='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + archive_cmds_CXX='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + archive_cmds_CXX='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + fi + else + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + fi + ;; + esac + ;; + interix[3-9]*) + hardcode_direct_CXX=no + hardcode_shlibpath_var_CXX=no + hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' + export_dynamic_flag_spec_CXX='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + archive_cmds_CXX='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + archive_expsym_cmds_CXX='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + irix5* | irix6*) + case $cc_basename in + CC*) + # SGI C++ + archive_cmds_CXX='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + + # Archives containing C++ object files must be created using + # "CC -ar", where "CC" is the IRIX C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + old_archive_cmds_CXX='$CC -ar -WR,-u -o $oldlib $oldobjs' + ;; + *) + if test "$GXX" = yes; then + if test "$with_gnu_ld" = no; then + archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` -o $lib' + fi + fi + link_all_deplibs_CXX=yes + ;; + esac + hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator_CXX=: + ;; + linux* | k*bsd*-gnu) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + archive_expsym_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | grep "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + + hardcode_libdir_flag_spec_CXX='${wl}--rpath,$libdir' + export_dynamic_flag_spec_CXX='${wl}--export-dynamic' + + # Archives containing C++ object files must be created using + # "CC -Bstatic", where "CC" is the KAI C++ compiler. + old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs' + ;; + icpc*) + # Intel C++ + with_gnu_ld=yes + # version 8.0 and above of icpc choke on multiply defined symbols + # if we add $predep_objects and $postdep_objects, however 7.1 and + # earlier do not add the objects themselves. + case `$CC -V 2>&1` in + *"Version 7."*) + archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + ;; + *) # Version 8.0 or newer + tmp_idyn= + case $host_cpu in + ia64*) tmp_idyn=' -i_dynamic';; + esac + archive_cmds_CXX='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_CXX='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + ;; + esac + archive_cmds_need_lc_CXX=no + hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' + export_dynamic_flag_spec_CXX='${wl}--export-dynamic' + whole_archive_flag_spec_CXX='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + ;; + pgCC* | pgcpp*) + # Portland Group C++ compiler + archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' + archive_expsym_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' + + hardcode_libdir_flag_spec_CXX='${wl}--rpath ${wl}$libdir' + export_dynamic_flag_spec_CXX='${wl}--export-dynamic' + whole_archive_flag_spec_CXX='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' + ;; + cxx*) + # Compaq C++ + archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols' + + runpath_var=LD_RUN_PATH + hardcode_libdir_flag_spec_CXX='-rpath $libdir' + hardcode_libdir_separator_CXX=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + no_undefined_flag_CXX=' -zdefs' + archive_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + archive_expsym_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols' + hardcode_libdir_flag_spec_CXX='-R$libdir' + whole_archive_flag_spec_CXX='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' + + # Not sure whether something based on + # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 + # would be better. + output_verbose_link_cmd='echo' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + old_archive_cmds_CXX='$CC -xar -o $oldlib $oldobjs' + ;; + esac + ;; + esac + ;; + lynxos*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + m88k*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + mvs*) + case $cc_basename in + cxx*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + netbsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + archive_cmds_CXX='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' + wlarc= + hardcode_libdir_flag_spec_CXX='-R$libdir' + hardcode_direct_CXX=yes + hardcode_shlibpath_var_CXX=no + fi + # Workaround some broken pre-1.5 toolchains + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' + ;; + openbsd2*) + # C++ shared libraries are fairly broken + ld_shlibs_CXX=no + ;; + openbsd*) + if test -f /usr/libexec/ld.so; then + hardcode_direct_CXX=yes + hardcode_shlibpath_var_CXX=no + archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + archive_expsym_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib' + export_dynamic_flag_spec_CXX='${wl}-E' + whole_archive_flag_spec_CXX="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + fi + output_verbose_link_cmd='echo' + else + ld_shlibs_CXX=no + fi + ;; + osf3*) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + + hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' + hardcode_libdir_separator_CXX=: + + # Archives containing C++ object files must be created using + # "CC -Bstatic", where "CC" is the KAI C++ compiler. + old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs' + + ;; + RCC*) + # Rational C++ 2.4.1 + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + cxx*) + allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds_CXX='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && echo ${wl}-set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + + hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator_CXX=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld" | grep -v "ld:"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + *) + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds_CXX='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + + hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator_CXX=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"' + + else + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + fi + ;; + esac + ;; + osf4* | osf5*) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + + hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' + hardcode_libdir_separator_CXX=: + + # Archives containing C++ object files must be created using + # the KAI C++ compiler. + old_archive_cmds_CXX='$CC -o $oldlib $oldobjs' + ;; + RCC*) + # Rational C++ 2.4.1 + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + cxx*) + allow_undefined_flag_CXX=' -expect_unresolved \*' + archive_cmds_CXX='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + archive_expsym_cmds_CXX='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ + echo "-hidden">> $lib.exp~ + $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname -Wl,-input -Wl,$lib.exp `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib~ + $rm $lib.exp' + + hardcode_libdir_flag_spec_CXX='-rpath $libdir' + hardcode_libdir_separator_CXX=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld" | grep -v "ld:"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + *) + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds_CXX='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + + hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator_CXX=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"' + + else + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + fi + ;; + esac + ;; + psos*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + lcc*) + # Lucid + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + solaris*) + case $cc_basename in + CC*) + # Sun C++ 4.2, 5.x and Centerline C++ + archive_cmds_need_lc_CXX=yes + no_undefined_flag_CXX=' -zdefs' + archive_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + archive_expsym_cmds_CXX='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp' + + hardcode_libdir_flag_spec_CXX='-R$libdir' + hardcode_shlibpath_var_CXX=no + case $host_os in + solaris2.[0-5] | solaris2.[0-5].*) ;; + *) + # The compiler driver will combine and reorder linker options, + # but understands `-z linker_flag'. + # Supported since Solaris 2.6 (maybe 2.5.1?) + whole_archive_flag_spec_CXX='-z allextract$convenience -z defaultextract' + ;; + esac + link_all_deplibs_CXX=yes + + output_verbose_link_cmd='echo' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + old_archive_cmds_CXX='$CC -xar -o $oldlib $oldobjs' + ;; + gcx*) + # Green Hills C++ Compiler + archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + + # The C++ compiler must be used to create the archive. + old_archive_cmds_CXX='$CC $LDFLAGS -archive -o $oldlib $oldobjs' + ;; + *) + # GNU C++ compiler with Solaris linker + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + no_undefined_flag_CXX=' ${wl}-z ${wl}defs' + if $CC --version | grep -v '^2\.7' > /dev/null; then + archive_cmds_CXX='$CC -shared -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + archive_expsym_cmds_CXX='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -shared -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd="$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep \"\-L\"" + else + # g++ 2.7 appears to require `-G' NOT `-shared' on this + # platform. + archive_cmds_CXX='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + archive_expsym_cmds_CXX='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd="$CC -G $CFLAGS -v conftest.$objext 2>&1 | grep \"\-L\"" + fi + + hardcode_libdir_flag_spec_CXX='${wl}-R $wl$libdir' + case $host_os in + solaris2.[0-5] | solaris2.[0-5].*) ;; + *) + whole_archive_flag_spec_CXX='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' + ;; + esac + fi + ;; + esac + ;; + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) + no_undefined_flag_CXX='${wl}-z,text' + archive_cmds_need_lc_CXX=no + hardcode_shlibpath_var_CXX=no + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + archive_cmds_CXX='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_CXX='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + archive_cmds_CXX='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_CXX='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + # For security reasons, it is highly recommended that you always + # use absolute paths for naming shared libraries, and exclude the + # DT_RUNPATH tag from executables and libraries. But doing so + # requires that you compile everything twice, which is a pain. + # So that behaviour is only enabled if SCOABSPATH is set to a + # non-empty value in the environment. Most likely only useful for + # creating official distributions of packages. + # This is a hack until libtool officially supports absolute path + # names for shared libraries. + no_undefined_flag_CXX='${wl}-z,text' + allow_undefined_flag_CXX='${wl}-z,nodefs' + archive_cmds_need_lc_CXX=no + hardcode_shlibpath_var_CXX=no + hardcode_libdir_flag_spec_CXX='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`' + hardcode_libdir_separator_CXX=':' + link_all_deplibs_CXX=yes + export_dynamic_flag_spec_CXX='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + archive_cmds_CXX='$CC -G ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_CXX='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + archive_cmds_CXX='$CC -shared ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_CXX='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + vxworks*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; +esac +{ echo "$as_me:$LINENO: result: $ld_shlibs_CXX" >&5 +echo "${ECHO_T}$ld_shlibs_CXX" >&6; } +test "$ld_shlibs_CXX" = no && can_build_shared=no + +GCC_CXX="$GXX" +LD_CXX="$LD" + +cat > conftest.$ac_ext <&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # Parse the compiler output and extract the necessary + # objects, libraries and library flags. + + # Sentinel used to keep track of whether or not we are before + # the conftest object file. + pre_test_object_deps_done=no + + # The `*' in the case matches for architectures that use `case' in + # $output_verbose_cmd can trigger glob expansion during the loop + # eval without this substitution. + output_verbose_link_cmd=`$echo "X$output_verbose_link_cmd" | $Xsed -e "$no_glob_subst"` + + for p in `eval $output_verbose_link_cmd`; do + case $p in + + -L* | -R* | -l*) + # Some compilers place space between "-{L,R}" and the path. + # Remove the space. + if test $p = "-L" \ + || test $p = "-R"; then + prev=$p + continue + else + prev= + fi + + if test "$pre_test_object_deps_done" = no; then + case $p in + -L* | -R*) + # Internal compiler library paths should come after those + # provided the user. The postdeps already come after the + # user supplied libs so there is no need to process them. + if test -z "$compiler_lib_search_path_CXX"; then + compiler_lib_search_path_CXX="${prev}${p}" + else + compiler_lib_search_path_CXX="${compiler_lib_search_path_CXX} ${prev}${p}" + fi + ;; + # The "-l" case would never come before the object being + # linked, so don't bother handling this case. + esac + else + if test -z "$postdeps_CXX"; then + postdeps_CXX="${prev}${p}" + else + postdeps_CXX="${postdeps_CXX} ${prev}${p}" + fi + fi + ;; + + *.$objext) + # This assumes that the test object file only shows up + # once in the compiler output. + if test "$p" = "conftest.$objext"; then + pre_test_object_deps_done=yes + continue + fi + + if test "$pre_test_object_deps_done" = no; then + if test -z "$predep_objects_CXX"; then + predep_objects_CXX="$p" + else + predep_objects_CXX="$predep_objects_CXX $p" + fi + else + if test -z "$postdep_objects_CXX"; then + postdep_objects_CXX="$p" + else + postdep_objects_CXX="$postdep_objects_CXX $p" + fi + fi + ;; + + *) ;; # Ignore the rest. + + esac + done + + # Clean up. + rm -f a.out a.exe +else + echo "libtool.m4: error: problem compiling CXX test program" +fi + +$rm -f confest.$objext + +compiler_lib_search_dirs_CXX= +if test -n "$compiler_lib_search_path_CXX"; then + compiler_lib_search_dirs_CXX=`echo " ${compiler_lib_search_path_CXX}" | ${SED} -e 's! -L! !g' -e 's!^ !!'` +fi + +# PORTME: override above test on systems where it is broken +case $host_os in +interix[3-9]*) + # Interix 3.5 installs completely hosed .la files for C++, so rather than + # hack all around it, let's just trust "g++" to DTRT. + predep_objects_CXX= + postdep_objects_CXX= + postdeps_CXX= + ;; + +linux*) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + # + # The more standards-conforming stlport4 library is + # incompatible with the Cstd library. Avoid specifying + # it if it's in CXXFLAGS. Ignore libCrun as + # -library=stlport4 depends on it. + case " $CXX $CXXFLAGS " in + *" -library=stlport4 "*) + solaris_use_stlport4=yes + ;; + esac + if test "$solaris_use_stlport4" != yes; then + postdeps_CXX='-library=Cstd -library=Crun' + fi + ;; + esac + ;; + +solaris*) + case $cc_basename in + CC*) + # The more standards-conforming stlport4 library is + # incompatible with the Cstd library. Avoid specifying + # it if it's in CXXFLAGS. Ignore libCrun as + # -library=stlport4 depends on it. + case " $CXX $CXXFLAGS " in + *" -library=stlport4 "*) + solaris_use_stlport4=yes + ;; + esac + + # Adding this requires a known-good setup of shared libraries for + # Sun compiler versions before 5.6, else PIC objects from an old + # archive will be linked into the output, leading to subtle bugs. + if test "$solaris_use_stlport4" != yes; then + postdeps_CXX='-library=Cstd -library=Crun' + fi + ;; + esac + ;; +esac + +case " $postdeps_CXX " in +*" -lc "*) archive_cmds_need_lc_CXX=no ;; +esac + +lt_prog_compiler_wl_CXX= +lt_prog_compiler_pic_CXX= +lt_prog_compiler_static_CXX= + +{ echo "$as_me:$LINENO: checking for $compiler option to produce PIC" >&5 +echo $ECHO_N "checking for $compiler option to produce PIC... $ECHO_C" >&6; } + + # C++ specific cases for pic, static, wl, etc. + if test "$GXX" = yes; then + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_static_CXX='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static_CXX='-Bstatic' + fi + ;; + amigaos*) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + lt_prog_compiler_pic_CXX='-m68020 -resident32 -malways-restore-a4' + ;; + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + mingw* | cygwin* | os2* | pw32*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + # Although the cygwin gcc ignores -fPIC, still need this for old-style + # (--disable-auto-import) libraries + lt_prog_compiler_pic_CXX='-DDLL_EXPORT' + ;; + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + lt_prog_compiler_pic_CXX='-fno-common' + ;; + *djgpp*) + # DJGPP does not support shared libraries at all + lt_prog_compiler_pic_CXX= + ;; + interix[3-9]*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + sysv4*MP*) + if test -d /usr/nec; then + lt_prog_compiler_pic_CXX=-Kconform_pic + fi + ;; + hpux*) + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + ;; + *) + lt_prog_compiler_pic_CXX='-fPIC' + ;; + esac + ;; + *) + lt_prog_compiler_pic_CXX='-fPIC' + ;; + esac + else + case $host_os in + aix[4-9]*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static_CXX='-Bstatic' + else + lt_prog_compiler_static_CXX='-bnso -bI:/lib/syscalls.exp' + fi + ;; + chorus*) + case $cc_basename in + cxch68*) + # Green Hills C++ Compiler + # _LT_AC_TAGVAR(lt_prog_compiler_static, CXX)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" + ;; + esac + ;; + darwin*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + case $cc_basename in + xlc*) + lt_prog_compiler_pic_CXX='-qnocommon' + lt_prog_compiler_wl_CXX='-Wl,' + ;; + esac + ;; + dgux*) + case $cc_basename in + ec++*) + lt_prog_compiler_pic_CXX='-KPIC' + ;; + ghcx*) + # Green Hills C++ Compiler + lt_prog_compiler_pic_CXX='-pic' + ;; + *) + ;; + esac + ;; + freebsd* | dragonfly*) + # FreeBSD uses GNU C++ + ;; + hpux9* | hpux10* | hpux11*) + case $cc_basename in + CC*) + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_static_CXX='${wl}-a ${wl}archive' + if test "$host_cpu" != ia64; then + lt_prog_compiler_pic_CXX='+Z' + fi + ;; + aCC*) + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_static_CXX='${wl}-a ${wl}archive' + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic_CXX='+Z' + ;; + esac + ;; + *) + ;; + esac + ;; + interix*) + # This is c89, which is MS Visual C++ (no shared libs) + # Anyone wants to do a port? + ;; + irix5* | irix6* | nonstopux*) + case $cc_basename in + CC*) + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_static_CXX='-non_shared' + # CC pic flag -KPIC is the default. + ;; + *) + ;; + esac + ;; + linux* | k*bsd*-gnu) + case $cc_basename in + KCC*) + # KAI C++ Compiler + lt_prog_compiler_wl_CXX='--backend -Wl,' + lt_prog_compiler_pic_CXX='-fPIC' + ;; + icpc* | ecpc*) + # Intel C++ + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_pic_CXX='-KPIC' + lt_prog_compiler_static_CXX='-static' + ;; + pgCC* | pgcpp*) + # Portland Group C++ compiler. + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_pic_CXX='-fpic' + lt_prog_compiler_static_CXX='-Bstatic' + ;; + cxx*) + # Compaq C++ + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + lt_prog_compiler_pic_CXX= + lt_prog_compiler_static_CXX='-non_shared' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + lt_prog_compiler_pic_CXX='-KPIC' + lt_prog_compiler_static_CXX='-Bstatic' + lt_prog_compiler_wl_CXX='-Qoption ld ' + ;; + esac + ;; + esac + ;; + lynxos*) + ;; + m88k*) + ;; + mvs*) + case $cc_basename in + cxx*) + lt_prog_compiler_pic_CXX='-W c,exportall' + ;; + *) + ;; + esac + ;; + netbsd*) + ;; + osf3* | osf4* | osf5*) + case $cc_basename in + KCC*) + lt_prog_compiler_wl_CXX='--backend -Wl,' + ;; + RCC*) + # Rational C++ 2.4.1 + lt_prog_compiler_pic_CXX='-pic' + ;; + cxx*) + # Digital/Compaq C++ + lt_prog_compiler_wl_CXX='-Wl,' + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + lt_prog_compiler_pic_CXX= + lt_prog_compiler_static_CXX='-non_shared' + ;; + *) + ;; + esac + ;; + psos*) + ;; + solaris*) + case $cc_basename in + CC*) + # Sun C++ 4.2, 5.x and Centerline C++ + lt_prog_compiler_pic_CXX='-KPIC' + lt_prog_compiler_static_CXX='-Bstatic' + lt_prog_compiler_wl_CXX='-Qoption ld ' + ;; + gcx*) + # Green Hills C++ Compiler + lt_prog_compiler_pic_CXX='-PIC' + ;; + *) + ;; + esac + ;; + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + lt_prog_compiler_pic_CXX='-pic' + lt_prog_compiler_static_CXX='-Bstatic' + ;; + lcc*) + # Lucid + lt_prog_compiler_pic_CXX='-pic' + ;; + *) + ;; + esac + ;; + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + lt_prog_compiler_pic_CXX='-KPIC' + ;; + *) + ;; + esac + ;; + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + case $cc_basename in + CC*) + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_pic_CXX='-KPIC' + lt_prog_compiler_static_CXX='-Bstatic' + ;; + esac + ;; + vxworks*) + ;; + *) + lt_prog_compiler_can_build_shared_CXX=no + ;; + esac + fi + +{ echo "$as_me:$LINENO: result: $lt_prog_compiler_pic_CXX" >&5 +echo "${ECHO_T}$lt_prog_compiler_pic_CXX" >&6; } + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$lt_prog_compiler_pic_CXX"; then + +{ echo "$as_me:$LINENO: checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works" >&5 +echo $ECHO_N "checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works... $ECHO_C" >&6; } +if test "${lt_cv_prog_compiler_pic_works_CXX+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_cv_prog_compiler_pic_works_CXX=no + ac_outfile=conftest.$ac_objext + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$lt_prog_compiler_pic_CXX -DPIC" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:12837: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:12841: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_pic_works_CXX=yes + fi + fi + $rm conftest* + +fi +{ echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_pic_works_CXX" >&5 +echo "${ECHO_T}$lt_cv_prog_compiler_pic_works_CXX" >&6; } + +if test x"$lt_cv_prog_compiler_pic_works_CXX" = xyes; then + case $lt_prog_compiler_pic_CXX in + "" | " "*) ;; + *) lt_prog_compiler_pic_CXX=" $lt_prog_compiler_pic_CXX" ;; + esac +else + lt_prog_compiler_pic_CXX= + lt_prog_compiler_can_build_shared_CXX=no +fi + +fi +case $host_os in + # For platforms which do not support PIC, -DPIC is meaningless: + *djgpp*) + lt_prog_compiler_pic_CXX= + ;; + *) + lt_prog_compiler_pic_CXX="$lt_prog_compiler_pic_CXX -DPIC" + ;; +esac + +# +# Check to make sure the static flag actually works. +# +wl=$lt_prog_compiler_wl_CXX eval lt_tmp_static_flag=\"$lt_prog_compiler_static_CXX\" +{ echo "$as_me:$LINENO: checking if $compiler static flag $lt_tmp_static_flag works" >&5 +echo $ECHO_N "checking if $compiler static flag $lt_tmp_static_flag works... $ECHO_C" >&6; } +if test "${lt_cv_prog_compiler_static_works_CXX+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_cv_prog_compiler_static_works_CXX=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $lt_tmp_static_flag" + echo "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&5 + $echo "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_static_works_CXX=yes + fi + else + lt_cv_prog_compiler_static_works_CXX=yes + fi + fi + $rm -r conftest* + LDFLAGS="$save_LDFLAGS" + +fi +{ echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_static_works_CXX" >&5 +echo "${ECHO_T}$lt_cv_prog_compiler_static_works_CXX" >&6; } + +if test x"$lt_cv_prog_compiler_static_works_CXX" = xyes; then + : +else + lt_prog_compiler_static_CXX= +fi + + +{ echo "$as_me:$LINENO: checking if $compiler supports -c -o file.$ac_objext" >&5 +echo $ECHO_N "checking if $compiler supports -c -o file.$ac_objext... $ECHO_C" >&6; } +if test "${lt_cv_prog_compiler_c_o_CXX+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_cv_prog_compiler_c_o_CXX=no + $rm -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:12941: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:12945: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + lt_cv_prog_compiler_c_o_CXX=yes + fi + fi + chmod u+w . 2>&5 + $rm conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $rm out/ii_files/* && rmdir out/ii_files + $rm out/* && rmdir out + cd .. + rmdir conftest + $rm conftest* + +fi +{ echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_c_o_CXX" >&5 +echo "${ECHO_T}$lt_cv_prog_compiler_c_o_CXX" >&6; } + + +hard_links="nottested" +if test "$lt_cv_prog_compiler_c_o_CXX" = no && test "$need_locks" != no; then + # do not overwrite the value of need_locks provided by the user + { echo "$as_me:$LINENO: checking if we can lock with hard links" >&5 +echo $ECHO_N "checking if we can lock with hard links... $ECHO_C" >&6; } + hard_links=yes + $rm conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + { echo "$as_me:$LINENO: result: $hard_links" >&5 +echo "${ECHO_T}$hard_links" >&6; } + if test "$hard_links" = no; then + { echo "$as_me:$LINENO: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 +echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} + need_locks=warn + fi +else + need_locks=no +fi + +{ echo "$as_me:$LINENO: checking whether the $compiler linker ($LD) supports shared libraries" >&5 +echo $ECHO_N "checking whether the $compiler linker ($LD) supports shared libraries... $ECHO_C" >&6; } + + export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + case $host_os in + aix[4-9]*) + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + if $NM -V 2>&1 | grep 'GNU' > /dev/null; then + export_symbols_cmds_CXX='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols' + else + export_symbols_cmds_CXX='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols' + fi + ;; + pw32*) + export_symbols_cmds_CXX="$ltdll_cmds" + ;; + cygwin* | mingw*) + export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;/^.*[ ]__nm__/s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols' + ;; + *) + export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + ;; + esac + exclude_expsyms_CXX='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*' + +{ echo "$as_me:$LINENO: result: $ld_shlibs_CXX" >&5 +echo "${ECHO_T}$ld_shlibs_CXX" >&6; } +test "$ld_shlibs_CXX" = no && can_build_shared=no + +# +# Do we need to explicitly link libc? +# +case "x$archive_cmds_need_lc_CXX" in +x|xyes) + # Assume -lc should be added + archive_cmds_need_lc_CXX=yes + + if test "$enable_shared" = yes && test "$GCC" = yes; then + case $archive_cmds_CXX in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + { echo "$as_me:$LINENO: checking whether -lc should be explicitly linked in" >&5 +echo $ECHO_N "checking whether -lc should be explicitly linked in... $ECHO_C" >&6; } + $rm conftest* + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$lt_prog_compiler_wl_CXX + pic_flag=$lt_prog_compiler_pic_CXX + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$allow_undefined_flag_CXX + allow_undefined_flag_CXX= + if { (eval echo "$as_me:$LINENO: \"$archive_cmds_CXX 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1\"") >&5 + (eval $archive_cmds_CXX 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + then + archive_cmds_need_lc_CXX=no + else + archive_cmds_need_lc_CXX=yes + fi + allow_undefined_flag_CXX=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $rm conftest* + { echo "$as_me:$LINENO: result: $archive_cmds_need_lc_CXX" >&5 +echo "${ECHO_T}$archive_cmds_need_lc_CXX" >&6; } + ;; + esac + fi + ;; +esac + +{ echo "$as_me:$LINENO: checking dynamic linker characteristics" >&5 +echo $ECHO_N "checking dynamic linker characteristics... $ECHO_C" >&6; } +library_names_spec= +libname_spec='lib$name' +soname_spec= +shrext_cmds=".so" +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" + +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + +case $host_os in +aix3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='${libname}${release}${shared_ext}$major' + ;; + +aix[4-9]*) + version_type=linux + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test "$host_cpu" = ia64; then + # AIX 5 supports IA64 + library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line `#! .'. This would cause the generated library to + # depend on `.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[01] | aix4.[01].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # AIX (on Power*) has no versioning support, so currently we can not hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + if test "$aix_use_runtimelinking" = yes; then + # If using run time linking (on AIX 4.2 or later) use lib.so + # instead of lib.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + else + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='${libname}${release}.a $libname.a' + soname_spec='${libname}${release}${shared_ext}$major' + fi + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' + ;; + +beos*) + library_names_spec='${libname}${shared_ext}' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi[45]*) + version_type=linux + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32*) + version_type=windows + shrext_cmds=".dll" + need_version=no + need_lib_prefix=no + + case $GCC,$host_os in + yes,cygwin* | yes,mingw* | yes,pw32*) + library_names_spec='$libname.dll.a' + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i;echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $rm \$dlpath' + shlibpath_overrides_runpath=yes + + case $host_os in + cygwin*) + # Cygwin DLLs use 'cyg' prefix rather than 'lib' + soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib" + ;; + mingw*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if echo "$sys_lib_search_path_spec" | grep ';[c-zC-Z]:/' >/dev/null; then + # It is most probably a Windows format PATH printed by + # mingw gcc, but we are running on Cygwin. Gcc prints its search + # path with ; separators, and with drive letters. We can handle the + # drive letters (cygwin fileutils understands them), so leave them, + # especially as we might pass files found there to a mingw objdump, + # which wouldn't understand a cygwinified path. Ahh. + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + ;; + pw32*) + # pw32 DLLs use 'pw' prefix rather than 'lib' + library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + ;; + esac + ;; + + *) + library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' + ;; + esac + dynamic_linker='Win32 ld.exe' + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${versuffix}$shared_ext ${libname}${release}${major}$shared_ext ${libname}$shared_ext' + soname_spec='${libname}${release}${major}$shared_ext' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' + + sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd1*) + dynamic_linker=no + ;; + +freebsd* | dragonfly*) + # DragonFly does not have aout. When/if they implement a new + # versioning mechanism, adjust this. + if test -x /usr/bin/objformat; then + objformat=`/usr/bin/objformat` + else + case $host_os in + freebsd[123]*) objformat=aout ;; + *) objformat=elf ;; + esac + fi + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[01]* | freebsdelf3.[01]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ + freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + *) # from 4.6 on, and DragonFly + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + esac + ;; + +gnu*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + case $host_cpu in + ia64*) + shrext_cmds='.so' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + if test "X$HPUX_IA64_MODE" = X32; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + fi + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + hppa*64*) + shrext_cmds='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) + shrext_cmds='.sl' + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + ;; + esac + # HP-UX runs *really* slowly unless shared libraries are mode 555. + postinstall_cmds='chmod 555 $lib' + ;; + +interix[3-9]*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) + if test "$lt_cv_prog_gnu_ld" = yes; then + version_type=linux + else + version_type=irix + fi ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") + libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") + libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") + libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" + sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" + hardcode_into_libs=yes + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +# This must be Linux ELF. +linux* | k*bsd*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # Append ld.so.conf contents to the search path + if test -f /etc/ld.so.conf; then + lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '` + sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" + fi + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +nto-qnx*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +openbsd*) + version_type=sunos + sys_lib_dlsearch_path_spec="/usr/lib" + need_lib_prefix=no + # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. + case $host_os in + openbsd3.3 | openbsd3.3.*) need_version=yes ;; + *) need_version=no ;; + esac + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + case $host_os in + openbsd2.[89] | openbsd2.[89].*) + shlibpath_overrides_runpath=no + ;; + *) + shlibpath_overrides_runpath=yes + ;; + esac + else + shlibpath_overrides_runpath=yes + fi + ;; + +os2*) + libname_spec='$name' + shrext_cmds=".dll" + need_lib_prefix=no + library_names_spec='$libname${shared_ext} $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + ;; + +rdos*) + dynamic_linker=no + ;; + +solaris*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + export_dynamic_flag_spec='${wl}-Blargedynsym' + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec ;then + version_type=linux + library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' + soname_spec='$libname${shared_ext}.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + version_type=freebsd-elf + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + if test "$with_gnu_ld" = yes; then + sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' + shlibpath_overrides_runpath=no + else + sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' + shlibpath_overrides_runpath=yes + case $host_os in + sco3.2v5*) + sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" + ;; + esac + fi + sys_lib_dlsearch_path_spec='/usr/lib' + ;; + +uts4*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +{ echo "$as_me:$LINENO: result: $dynamic_linker" >&5 +echo "${ECHO_T}$dynamic_linker" >&6; } +test "$dynamic_linker" = no && can_build_shared=no + +if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_cv_sys_lib_search_path_spec="$sys_lib_search_path_spec" +fi + +sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" +if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_cv_sys_lib_dlsearch_path_spec="$sys_lib_dlsearch_path_spec" +fi + +sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test "$GCC" = yes; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +{ echo "$as_me:$LINENO: checking how to hardcode library paths into programs" >&5 +echo $ECHO_N "checking how to hardcode library paths into programs... $ECHO_C" >&6; } +hardcode_action_CXX= +if test -n "$hardcode_libdir_flag_spec_CXX" || \ + test -n "$runpath_var_CXX" || \ + test "X$hardcode_automatic_CXX" = "Xyes" ; then + + # We can hardcode non-existant directories. + if test "$hardcode_direct_CXX" != no && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test "$_LT_AC_TAGVAR(hardcode_shlibpath_var, CXX)" != no && + test "$hardcode_minus_L_CXX" != no; then + # Linking always hardcodes the temporary library directory. + hardcode_action_CXX=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + hardcode_action_CXX=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + hardcode_action_CXX=unsupported +fi +{ echo "$as_me:$LINENO: result: $hardcode_action_CXX" >&5 +echo "${ECHO_T}$hardcode_action_CXX" >&6; } + +if test "$hardcode_action_CXX" = relink; then + # Fast installation is not supported + enable_fast_install=no +elif test "$shlibpath_overrides_runpath" = yes || + test "$enable_shared" = no; then + # Fast installation is not necessary + enable_fast_install=needless +fi + + +# The else clause should only fire when bootstrapping the +# libtool distribution, otherwise you forgot to ship ltmain.sh +# with your package, and you will get complaints that there are +# no rules to generate ltmain.sh. +if test -f "$ltmain"; then + # See if we are running on zsh, and set the options which allow our commands through + # without removal of \ escapes. + if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST + fi + # Now quote all the things that may contain metacharacters while being + # careful not to overquote the AC_SUBSTed values. We take copies of the + # variables and quote the copies for generation of the libtool script. + for var in echo old_CC old_CFLAGS AR AR_FLAGS EGREP RANLIB LN_S LTCC LTCFLAGS NM \ + SED SHELL STRIP \ + libname_spec library_names_spec soname_spec extract_expsyms_cmds \ + old_striplib striplib file_magic_cmd finish_cmds finish_eval \ + deplibs_check_method reload_flag reload_cmds need_locks \ + lt_cv_sys_global_symbol_pipe lt_cv_sys_global_symbol_to_cdecl \ + lt_cv_sys_global_symbol_to_c_name_address \ + sys_lib_search_path_spec sys_lib_dlsearch_path_spec \ + old_postinstall_cmds old_postuninstall_cmds \ + compiler_CXX \ + CC_CXX \ + LD_CXX \ + lt_prog_compiler_wl_CXX \ + lt_prog_compiler_pic_CXX \ + lt_prog_compiler_static_CXX \ + lt_prog_compiler_no_builtin_flag_CXX \ + export_dynamic_flag_spec_CXX \ + thread_safe_flag_spec_CXX \ + whole_archive_flag_spec_CXX \ + enable_shared_with_static_runtimes_CXX \ + old_archive_cmds_CXX \ + old_archive_from_new_cmds_CXX \ + predep_objects_CXX \ + postdep_objects_CXX \ + predeps_CXX \ + postdeps_CXX \ + compiler_lib_search_path_CXX \ + compiler_lib_search_dirs_CXX \ + archive_cmds_CXX \ + archive_expsym_cmds_CXX \ + postinstall_cmds_CXX \ + postuninstall_cmds_CXX \ + old_archive_from_expsyms_cmds_CXX \ + allow_undefined_flag_CXX \ + no_undefined_flag_CXX \ + export_symbols_cmds_CXX \ + hardcode_libdir_flag_spec_CXX \ + hardcode_libdir_flag_spec_ld_CXX \ + hardcode_libdir_separator_CXX \ + hardcode_automatic_CXX \ + module_cmds_CXX \ + module_expsym_cmds_CXX \ + lt_cv_prog_compiler_c_o_CXX \ + fix_srcfile_path_CXX \ + exclude_expsyms_CXX \ + include_expsyms_CXX; do + + case $var in + old_archive_cmds_CXX | \ + old_archive_from_new_cmds_CXX | \ + archive_cmds_CXX | \ + archive_expsym_cmds_CXX | \ + module_cmds_CXX | \ + module_expsym_cmds_CXX | \ + old_archive_from_expsyms_cmds_CXX | \ + export_symbols_cmds_CXX | \ + extract_expsyms_cmds | reload_cmds | finish_cmds | \ + postinstall_cmds | postuninstall_cmds | \ + old_postinstall_cmds | old_postuninstall_cmds | \ + sys_lib_search_path_spec | sys_lib_dlsearch_path_spec) + # Double-quote double-evaled strings. + eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\"" + ;; + *) + eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\"" + ;; + esac + done + + case $lt_echo in + *'\$0 --fallback-echo"') + lt_echo=`$echo "X$lt_echo" | $Xsed -e 's/\\\\\\\$0 --fallback-echo"$/$0 --fallback-echo"/'` + ;; + esac + +cfgfile="$ofile" + + cat <<__EOF__ >> "$cfgfile" +# ### BEGIN LIBTOOL TAG CONFIG: $tagname + +# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: + +# Shell to use when invoking shell scripts. +SHELL=$lt_SHELL + +# Whether or not to build shared libraries. +build_libtool_libs=$enable_shared + +# Whether or not to build static libraries. +build_old_libs=$enable_static + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=$archive_cmds_need_lc_CXX + +# Whether or not to disallow shared libs when runtime libs are static +allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_CXX + +# Whether or not to optimize for fast installation. +fast_install=$enable_fast_install + +# The host system. +host_alias=$host_alias +host=$host +host_os=$host_os + +# The build system. +build_alias=$build_alias +build=$build +build_os=$build_os + +# An echo program that does not interpret backslashes. +echo=$lt_echo + +# The archiver. +AR=$lt_AR +AR_FLAGS=$lt_AR_FLAGS + +# A C compiler. +LTCC=$lt_LTCC + +# LTCC compiler flags. +LTCFLAGS=$lt_LTCFLAGS + +# A language-specific compiler. +CC=$lt_compiler_CXX + +# Is the compiler the GNU C compiler? +with_gcc=$GCC_CXX + +# An ERE matcher. +EGREP=$lt_EGREP + +# The linker used to build libraries. +LD=$lt_LD_CXX + +# Whether we need hard or soft links. +LN_S=$lt_LN_S + +# A BSD-compatible nm program. +NM=$lt_NM + +# A symbol stripping program +STRIP=$lt_STRIP + +# Used to examine libraries when file_magic_cmd begins "file" +MAGIC_CMD=$MAGIC_CMD + +# Used on cygwin: DLL creation program. +DLLTOOL="$DLLTOOL" + +# Used on cygwin: object dumper. +OBJDUMP="$OBJDUMP" + +# Used on cygwin: assembler. +AS="$AS" + +# The name of the directory that contains temporary libtool files. +objdir=$objdir + +# How to create reloadable object files. +reload_flag=$lt_reload_flag +reload_cmds=$lt_reload_cmds + +# How to pass a linker flag through the compiler. +wl=$lt_lt_prog_compiler_wl_CXX + +# Object file suffix (normally "o"). +objext="$ac_objext" + +# Old archive suffix (normally "a"). +libext="$libext" + +# Shared library suffix (normally ".so"). +shrext_cmds='$shrext_cmds' + +# Executable file suffix (normally ""). +exeext="$exeext" + +# Additional compiler flags for building library objects. +pic_flag=$lt_lt_prog_compiler_pic_CXX +pic_mode=$pic_mode + +# What is the maximum length of a command? +max_cmd_len=$lt_cv_sys_max_cmd_len + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$lt_lt_cv_prog_compiler_c_o_CXX + +# Must we lock files when doing compilation? +need_locks=$lt_need_locks + +# Do we need the lib prefix for modules? +need_lib_prefix=$need_lib_prefix + +# Do we need a version for libraries? +need_version=$need_version + +# Whether dlopen is supported. +dlopen_support=$enable_dlopen + +# Whether dlopen of programs is supported. +dlopen_self=$enable_dlopen_self + +# Whether dlopen of statically linked programs is supported. +dlopen_self_static=$enable_dlopen_self_static + +# Compiler flag to prevent dynamic linking. +link_static_flag=$lt_lt_prog_compiler_static_CXX + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_CXX + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_CXX + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec=$lt_whole_archive_flag_spec_CXX + +# Compiler flag to generate thread-safe objects. +thread_safe_flag_spec=$lt_thread_safe_flag_spec_CXX + +# Library versioning type. +version_type=$version_type + +# Format of library name prefix. +libname_spec=$lt_libname_spec + +# List of archive names. First name is the real one, the rest are links. +# The last name is the one that the linker finds with -lNAME. +library_names_spec=$lt_library_names_spec + +# The coded name of the library, if different from the real name. +soname_spec=$lt_soname_spec + +# Commands used to build and install an old-style archive. +RANLIB=$lt_RANLIB +old_archive_cmds=$lt_old_archive_cmds_CXX +old_postinstall_cmds=$lt_old_postinstall_cmds +old_postuninstall_cmds=$lt_old_postuninstall_cmds + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_CXX + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_CXX + +# Commands used to build and install a shared archive. +archive_cmds=$lt_archive_cmds_CXX +archive_expsym_cmds=$lt_archive_expsym_cmds_CXX +postinstall_cmds=$lt_postinstall_cmds +postuninstall_cmds=$lt_postuninstall_cmds + +# Commands used to build a loadable module (assumed same as above if empty) +module_cmds=$lt_module_cmds_CXX +module_expsym_cmds=$lt_module_expsym_cmds_CXX + +# Commands to strip libraries. +old_striplib=$lt_old_striplib +striplib=$lt_striplib + +# Dependencies to place before the objects being linked to create a +# shared library. +predep_objects=$lt_predep_objects_CXX + +# Dependencies to place after the objects being linked to create a +# shared library. +postdep_objects=$lt_postdep_objects_CXX + +# Dependencies to place before the objects being linked to create a +# shared library. +predeps=$lt_predeps_CXX + +# Dependencies to place after the objects being linked to create a +# shared library. +postdeps=$lt_postdeps_CXX + +# The directories searched by this compiler when creating a shared +# library +compiler_lib_search_dirs=$lt_compiler_lib_search_dirs_CXX + +# The library search path used internally by the compiler when linking +# a shared library. +compiler_lib_search_path=$lt_compiler_lib_search_path_CXX + +# Method to check whether dependent libraries are shared objects. +deplibs_check_method=$lt_deplibs_check_method + +# Command to use when deplibs_check_method == file_magic. +file_magic_cmd=$lt_file_magic_cmd + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$lt_allow_undefined_flag_CXX + +# Flag that forces no undefined symbols. +no_undefined_flag=$lt_no_undefined_flag_CXX + +# Commands used to finish a libtool library installation in a directory. +finish_cmds=$lt_finish_cmds + +# Same as above, but a single script fragment to be evaled but not shown. +finish_eval=$lt_finish_eval + +# Take the output of nm and produce a listing of raw symbols and C names. +global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe + +# Transform the output of nm in a proper C declaration +global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl + +# Transform the output of nm in a C name address pair +global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address + +# This is the shared library runtime path variable. +runpath_var=$runpath_var + +# This is the shared library path variable. +shlibpath_var=$shlibpath_var + +# Is shlibpath searched before the hard-coded library search path? +shlibpath_overrides_runpath=$shlibpath_overrides_runpath + +# How to hardcode a shared library path into an executable. +hardcode_action=$hardcode_action_CXX + +# Whether we should hardcode library paths into libraries. +hardcode_into_libs=$hardcode_into_libs + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist. +hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_CXX + +# If ld is used when linking, flag to hardcode \$libdir into +# a binary during linking. This must work even if \$libdir does +# not exist. +hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld_CXX + +# Whether we need a single -rpath flag with a separated argument. +hardcode_libdir_separator=$lt_hardcode_libdir_separator_CXX + +# Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the +# resulting binary. +hardcode_direct=$hardcode_direct_CXX + +# Set to yes if using the -LDIR flag during linking hardcodes DIR into the +# resulting binary. +hardcode_minus_L=$hardcode_minus_L_CXX + +# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into +# the resulting binary. +hardcode_shlibpath_var=$hardcode_shlibpath_var_CXX + +# Set to yes if building a shared library automatically hardcodes DIR into the library +# and all subsequent libraries and executables linked against it. +hardcode_automatic=$hardcode_automatic_CXX + +# Variables whose values should be saved in libtool wrapper scripts and +# restored at relink time. +variables_saved_for_relink="$variables_saved_for_relink" + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=$link_all_deplibs_CXX + +# Compile-time system search path for libraries +sys_lib_search_path_spec=$lt_sys_lib_search_path_spec + +# Run-time system search path for libraries +sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec + +# Fix the shell variable \$srcfile for the compiler. +fix_srcfile_path=$lt_fix_srcfile_path + +# Set to yes if exported symbols are required. +always_export_symbols=$always_export_symbols_CXX + +# The commands to list exported symbols. +export_symbols_cmds=$lt_export_symbols_cmds_CXX + +# The commands to extract the exported symbol list from a shared archive. +extract_expsyms_cmds=$lt_extract_expsyms_cmds + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms=$lt_exclude_expsyms_CXX + +# Symbols that must always be exported. +include_expsyms=$lt_include_expsyms_CXX + +# ### END LIBTOOL TAG CONFIG: $tagname + +__EOF__ + + +else + # If there is no Makefile yet, we rely on a make rule to execute + # `config.status --recheck' to rerun these tests and create the + # libtool script then. + ltmain_in=`echo $ltmain | sed -e 's/\.sh$/.in/'` + if test -f "$ltmain_in"; then + test -f Makefile && make "$ltmain" + 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 + +CC=$lt_save_CC +LDCXX=$LD +LD=$lt_save_LD +GCC=$lt_save_GCC +with_gnu_ldcxx=$with_gnu_ld +with_gnu_ld=$lt_save_with_gnu_ld +lt_cv_path_LDCXX=$lt_cv_path_LD +lt_cv_path_LD=$lt_save_path_LD +lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld +lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld + + else + tagname="" + fi + ;; + + F77) + if test -n "$F77" && test "X$F77" != "Xno"; then + +ac_ext=f +ac_compile='$F77 -c $FFLAGS conftest.$ac_ext >&5' +ac_link='$F77 -o conftest$ac_exeext $FFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_f77_compiler_gnu + + +archive_cmds_need_lc_F77=no +allow_undefined_flag_F77= +always_export_symbols_F77=no +archive_expsym_cmds_F77= +export_dynamic_flag_spec_F77= +hardcode_direct_F77=no +hardcode_libdir_flag_spec_F77= +hardcode_libdir_flag_spec_ld_F77= +hardcode_libdir_separator_F77= +hardcode_minus_L_F77=no +hardcode_automatic_F77=no +module_cmds_F77= +module_expsym_cmds_F77= +link_all_deplibs_F77=unknown +old_archive_cmds_F77=$old_archive_cmds +no_undefined_flag_F77= +whole_archive_flag_spec_F77= +enable_shared_with_static_runtimes_F77=no + +# Source file extension for f77 test sources. +ac_ext=f + +# Object file extension for compiled f77 test sources. +objext=o +objext_F77=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="\ + subroutine t + return + end +" + +# Code to be used in simple link tests +lt_simple_link_test_code="\ + program t + end +" + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC + + +# save warnings/boilerplate of simple test code +ac_outfile=conftest.$ac_objext +echo "$lt_simple_compile_test_code" >conftest.$ac_ext +eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_compiler_boilerplate=`cat conftest.err` +$rm conftest* + +ac_outfile=conftest.$ac_objext +echo "$lt_simple_link_test_code" >conftest.$ac_ext +eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_linker_boilerplate=`cat conftest.err` +$rm -r conftest* + + +# Allow CC to be a program name with arguments. +lt_save_CC="$CC" +CC=${F77-"f77"} +compiler=$CC +compiler_F77=$CC +for cc_temp in $compiler""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`$echo "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"` + + +{ echo "$as_me:$LINENO: checking if libtool supports shared libraries" >&5 +echo $ECHO_N "checking if libtool supports shared libraries... $ECHO_C" >&6; } +{ echo "$as_me:$LINENO: result: $can_build_shared" >&5 +echo "${ECHO_T}$can_build_shared" >&6; } + +{ echo "$as_me:$LINENO: checking whether to build shared libraries" >&5 +echo $ECHO_N "checking whether to build shared libraries... $ECHO_C" >&6; } +test "$can_build_shared" = "no" && enable_shared=no + +# On AIX, shared libraries and static libraries use the same namespace, and +# are all built from PIC. +case $host_os in +aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; +aix[4-9]*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; +esac +{ echo "$as_me:$LINENO: result: $enable_shared" >&5 +echo "${ECHO_T}$enable_shared" >&6; } + +{ echo "$as_me:$LINENO: checking whether to build static libraries" >&5 +echo $ECHO_N "checking whether to build static libraries... $ECHO_C" >&6; } +# Make sure either enable_shared or enable_static is yes. +test "$enable_shared" = yes || enable_static=yes +{ echo "$as_me:$LINENO: result: $enable_static" >&5 +echo "${ECHO_T}$enable_static" >&6; } + +GCC_F77="$G77" +LD_F77="$LD" + +lt_prog_compiler_wl_F77= +lt_prog_compiler_pic_F77= +lt_prog_compiler_static_F77= + +{ echo "$as_me:$LINENO: checking for $compiler option to produce PIC" >&5 +echo $ECHO_N "checking for $compiler option to produce PIC... $ECHO_C" >&6; } + + if test "$GCC" = yes; then + lt_prog_compiler_wl_F77='-Wl,' + lt_prog_compiler_static_F77='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static_F77='-Bstatic' + fi + ;; + + amigaos*) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + lt_prog_compiler_pic_F77='-m68020 -resident32 -malways-restore-a4' + ;; + + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + + mingw* | cygwin* | pw32* | os2*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + # Although the cygwin gcc ignores -fPIC, still need this for old-style + # (--disable-auto-import) libraries + lt_prog_compiler_pic_F77='-DDLL_EXPORT' + ;; + + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + lt_prog_compiler_pic_F77='-fno-common' + ;; + + interix[3-9]*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + + msdosdjgpp*) + # Just because we use GCC doesn't mean we suddenly get shared libraries + # on systems that don't support them. + lt_prog_compiler_can_build_shared_F77=no + enable_shared=no + ;; + + sysv4*MP*) + if test -d /usr/nec; then + lt_prog_compiler_pic_F77=-Kconform_pic + fi + ;; + + hpux*) + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic_F77='-fPIC' + ;; + esac + ;; + + *) + lt_prog_compiler_pic_F77='-fPIC' + ;; + esac + else + # PORTME Check for flag to pass linker flags through the system compiler. + case $host_os in + aix*) + lt_prog_compiler_wl_F77='-Wl,' + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static_F77='-Bstatic' + else + lt_prog_compiler_static_F77='-bnso -bI:/lib/syscalls.exp' + fi + ;; + darwin*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + case $cc_basename in + xlc*) + lt_prog_compiler_pic_F77='-qnocommon' + lt_prog_compiler_wl_F77='-Wl,' + ;; + esac + ;; + + mingw* | cygwin* | pw32* | os2*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + lt_prog_compiler_pic_F77='-DDLL_EXPORT' + ;; + + hpux9* | hpux10* | hpux11*) + lt_prog_compiler_wl_F77='-Wl,' + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic_F77='+Z' + ;; + esac + # Is there a better lt_prog_compiler_static that works with the bundled CC? + lt_prog_compiler_static_F77='${wl}-a ${wl}archive' + ;; + + irix5* | irix6* | nonstopux*) + lt_prog_compiler_wl_F77='-Wl,' + # PIC (with -KPIC) is the default. + lt_prog_compiler_static_F77='-non_shared' + ;; + + newsos6) + lt_prog_compiler_pic_F77='-KPIC' + lt_prog_compiler_static_F77='-Bstatic' + ;; + + linux* | k*bsd*-gnu) + case $cc_basename in + icc* | ecc*) + lt_prog_compiler_wl_F77='-Wl,' + lt_prog_compiler_pic_F77='-KPIC' + lt_prog_compiler_static_F77='-static' + ;; + pgcc* | pgf77* | pgf90* | pgf95*) + # Portland Group compilers (*not* the Pentium gcc compiler, + # which looks to be a dead project) + lt_prog_compiler_wl_F77='-Wl,' + lt_prog_compiler_pic_F77='-fpic' + lt_prog_compiler_static_F77='-Bstatic' + ;; + ccc*) + lt_prog_compiler_wl_F77='-Wl,' + # All Alpha code is PIC. + lt_prog_compiler_static_F77='-non_shared' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C 5.9 + lt_prog_compiler_pic_F77='-KPIC' + lt_prog_compiler_static_F77='-Bstatic' + lt_prog_compiler_wl_F77='-Wl,' + ;; + *Sun\ F*) + # Sun Fortran 8.3 passes all unrecognized flags to the linker + lt_prog_compiler_pic_F77='-KPIC' + lt_prog_compiler_static_F77='-Bstatic' + lt_prog_compiler_wl_F77='' + ;; + esac + ;; + esac + ;; + + osf3* | osf4* | osf5*) + lt_prog_compiler_wl_F77='-Wl,' + # All OSF/1 code is PIC. + lt_prog_compiler_static_F77='-non_shared' + ;; + + rdos*) + lt_prog_compiler_static_F77='-non_shared' + ;; + + solaris*) + lt_prog_compiler_pic_F77='-KPIC' + lt_prog_compiler_static_F77='-Bstatic' + case $cc_basename in + f77* | f90* | f95*) + lt_prog_compiler_wl_F77='-Qoption ld ';; + *) + lt_prog_compiler_wl_F77='-Wl,';; + esac + ;; + + sunos4*) + lt_prog_compiler_wl_F77='-Qoption ld ' + lt_prog_compiler_pic_F77='-PIC' + lt_prog_compiler_static_F77='-Bstatic' + ;; + + sysv4 | sysv4.2uw2* | sysv4.3*) + lt_prog_compiler_wl_F77='-Wl,' + lt_prog_compiler_pic_F77='-KPIC' + lt_prog_compiler_static_F77='-Bstatic' + ;; + + sysv4*MP*) + if test -d /usr/nec ;then + lt_prog_compiler_pic_F77='-Kconform_pic' + lt_prog_compiler_static_F77='-Bstatic' + fi + ;; + + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + lt_prog_compiler_wl_F77='-Wl,' + lt_prog_compiler_pic_F77='-KPIC' + lt_prog_compiler_static_F77='-Bstatic' + ;; + + unicos*) + lt_prog_compiler_wl_F77='-Wl,' + lt_prog_compiler_can_build_shared_F77=no + ;; + + uts4*) + lt_prog_compiler_pic_F77='-pic' + lt_prog_compiler_static_F77='-Bstatic' + ;; + + *) + lt_prog_compiler_can_build_shared_F77=no + ;; + esac + fi + +{ echo "$as_me:$LINENO: result: $lt_prog_compiler_pic_F77" >&5 +echo "${ECHO_T}$lt_prog_compiler_pic_F77" >&6; } + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$lt_prog_compiler_pic_F77"; then + +{ echo "$as_me:$LINENO: checking if $compiler PIC flag $lt_prog_compiler_pic_F77 works" >&5 +echo $ECHO_N "checking if $compiler PIC flag $lt_prog_compiler_pic_F77 works... $ECHO_C" >&6; } +if test "${lt_cv_prog_compiler_pic_works_F77+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_cv_prog_compiler_pic_works_F77=no + ac_outfile=conftest.$ac_objext + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$lt_prog_compiler_pic_F77" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:14524: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:14528: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_pic_works_F77=yes + fi + fi + $rm conftest* + +fi +{ echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_pic_works_F77" >&5 +echo "${ECHO_T}$lt_cv_prog_compiler_pic_works_F77" >&6; } + +if test x"$lt_cv_prog_compiler_pic_works_F77" = xyes; then + case $lt_prog_compiler_pic_F77 in + "" | " "*) ;; + *) lt_prog_compiler_pic_F77=" $lt_prog_compiler_pic_F77" ;; + esac +else + lt_prog_compiler_pic_F77= + lt_prog_compiler_can_build_shared_F77=no +fi + +fi +case $host_os in + # For platforms which do not support PIC, -DPIC is meaningless: + *djgpp*) + lt_prog_compiler_pic_F77= + ;; + *) + lt_prog_compiler_pic_F77="$lt_prog_compiler_pic_F77" + ;; +esac + +# +# Check to make sure the static flag actually works. +# +wl=$lt_prog_compiler_wl_F77 eval lt_tmp_static_flag=\"$lt_prog_compiler_static_F77\" +{ echo "$as_me:$LINENO: checking if $compiler static flag $lt_tmp_static_flag works" >&5 +echo $ECHO_N "checking if $compiler static flag $lt_tmp_static_flag works... $ECHO_C" >&6; } +if test "${lt_cv_prog_compiler_static_works_F77+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_cv_prog_compiler_static_works_F77=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $lt_tmp_static_flag" + echo "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&5 + $echo "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_static_works_F77=yes + fi + else + lt_cv_prog_compiler_static_works_F77=yes + fi + fi + $rm -r conftest* + LDFLAGS="$save_LDFLAGS" + +fi +{ echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_static_works_F77" >&5 +echo "${ECHO_T}$lt_cv_prog_compiler_static_works_F77" >&6; } + +if test x"$lt_cv_prog_compiler_static_works_F77" = xyes; then + : +else + lt_prog_compiler_static_F77= +fi + + +{ echo "$as_me:$LINENO: checking if $compiler supports -c -o file.$ac_objext" >&5 +echo $ECHO_N "checking if $compiler supports -c -o file.$ac_objext... $ECHO_C" >&6; } +if test "${lt_cv_prog_compiler_c_o_F77+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_cv_prog_compiler_c_o_F77=no + $rm -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:14628: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:14632: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + lt_cv_prog_compiler_c_o_F77=yes + fi + fi + chmod u+w . 2>&5 + $rm conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $rm out/ii_files/* && rmdir out/ii_files + $rm out/* && rmdir out + cd .. + rmdir conftest + $rm conftest* + +fi +{ echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_c_o_F77" >&5 +echo "${ECHO_T}$lt_cv_prog_compiler_c_o_F77" >&6; } + + +hard_links="nottested" +if test "$lt_cv_prog_compiler_c_o_F77" = no && test "$need_locks" != no; then + # do not overwrite the value of need_locks provided by the user + { echo "$as_me:$LINENO: checking if we can lock with hard links" >&5 +echo $ECHO_N "checking if we can lock with hard links... $ECHO_C" >&6; } + hard_links=yes + $rm conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + { echo "$as_me:$LINENO: result: $hard_links" >&5 +echo "${ECHO_T}$hard_links" >&6; } + if test "$hard_links" = no; then + { echo "$as_me:$LINENO: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 +echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} + need_locks=warn + fi +else + need_locks=no +fi + +{ echo "$as_me:$LINENO: checking whether the $compiler linker ($LD) supports shared libraries" >&5 +echo $ECHO_N "checking whether the $compiler linker ($LD) supports shared libraries... $ECHO_C" >&6; } + + runpath_var= + allow_undefined_flag_F77= + enable_shared_with_static_runtimes_F77=no + archive_cmds_F77= + archive_expsym_cmds_F77= + old_archive_From_new_cmds_F77= + old_archive_from_expsyms_cmds_F77= + export_dynamic_flag_spec_F77= + whole_archive_flag_spec_F77= + thread_safe_flag_spec_F77= + hardcode_libdir_flag_spec_F77= + hardcode_libdir_flag_spec_ld_F77= + hardcode_libdir_separator_F77= + hardcode_direct_F77=no + hardcode_minus_L_F77=no + hardcode_shlibpath_var_F77=unsupported + link_all_deplibs_F77=unknown + hardcode_automatic_F77=no + module_cmds_F77= + module_expsym_cmds_F77= + always_export_symbols_F77=no + export_symbols_cmds_F77='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + # include_expsyms should be a list of space-separated symbols to be *always* + # included in the symbol list + include_expsyms_F77= + # exclude_expsyms can be an extended regexp of symbols to exclude + # it will be wrapped by ` (' and `)$', so one must not match beginning or + # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', + # as well as any symbol that contains `d'. + exclude_expsyms_F77='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*' + # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out + # platforms (ab)use it in PIC code, but their linkers get confused if + # the symbol is explicitly referenced. Since portable code cannot + # rely on this symbol name, it's probably fine to never include it in + # preloaded symbol tables. + # Exclude shared library initialization/finalization symbols. + extract_expsyms_cmds= + # Just being paranoid about ensuring that cc_basename is set. + for cc_temp in $compiler""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`$echo "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"` + + case $host_os in + cygwin* | mingw* | pw32*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test "$GCC" != yes; then + with_gnu_ld=no + fi + ;; + interix*) + # we just hope/assume this is gcc and not c89 (= MSVC++) + with_gnu_ld=yes + ;; + openbsd*) + with_gnu_ld=no + ;; + esac + + ld_shlibs_F77=yes + if test "$with_gnu_ld" = yes; then + # If archive_cmds runs LD, not CC, wlarc should be empty + wlarc='${wl}' + + # Set some defaults for GNU ld with shared library support. These + # are reset later if shared libraries are not supported. Putting them + # here allows them to be overridden if necessary. + runpath_var=LD_RUN_PATH + hardcode_libdir_flag_spec_F77='${wl}--rpath ${wl}$libdir' + export_dynamic_flag_spec_F77='${wl}--export-dynamic' + # ancient GNU ld didn't support --whole-archive et. al. + if $LD --help 2>&1 | grep 'no-whole-archive' > /dev/null; then + whole_archive_flag_spec_F77="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + whole_archive_flag_spec_F77= + fi + supports_anon_versioning=no + case `$LD -v 2>/dev/null` in + *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11 + *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... + *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... + *\ 2.11.*) ;; # other 2.11 versions + *) supports_anon_versioning=yes ;; + esac + + # See if GNU ld supports shared libraries. + case $host_os in + aix[3-9]*) + # On AIX/PPC, the GNU linker is very broken + if test "$host_cpu" != ia64; then + ld_shlibs_F77=no + cat <&2 + +*** Warning: the GNU linker, at least up to release 2.9.1, is reported +*** to be unable to reliably create shared libraries on AIX. +*** Therefore, libtool is disabling shared libraries support. If you +*** really care for shared libraries, you may want to modify your PATH +*** so that a non-GNU linker is found, and then restart. + +EOF + fi + ;; + + amigaos*) + archive_cmds_F77='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec_F77='-L$libdir' + hardcode_minus_L_F77=yes + + # Samuel A. Falvo II reports + # that the semantics of dynamic libraries on AmigaOS, at least up + # to version 4, is to share data among multiple programs linked + # with the same dynamic library. Since this doesn't match the + # behavior of shared libraries on other platforms, we can't use + # them. + ld_shlibs_F77=no + ;; + + beos*) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + allow_undefined_flag_F77=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + archive_cmds_F77='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + ld_shlibs_F77=no + fi + ;; + + cygwin* | mingw* | pw32*) + # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, F77) is actually meaningless, + # as there is no search path for DLLs. + hardcode_libdir_flag_spec_F77='-L$libdir' + allow_undefined_flag_F77=unsupported + always_export_symbols_F77=no + enable_shared_with_static_runtimes_F77=yes + export_symbols_cmds_F77='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/'\'' -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols' + + if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then + archive_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + archive_expsym_cmds_F77='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + ld_shlibs_F77=no + fi + ;; + + interix[3-9]*) + hardcode_direct_F77=no + hardcode_shlibpath_var_F77=no + hardcode_libdir_flag_spec_F77='${wl}-rpath,$libdir' + export_dynamic_flag_spec_F77='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + archive_cmds_F77='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + archive_expsym_cmds_F77='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + + gnu* | linux* | k*bsd*-gnu) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + tmp_addflag= + case $cc_basename,$host_cpu in + pgcc*) # Portland Group C compiler + whole_archive_flag_spec_F77='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag' + ;; + pgf77* | pgf90* | pgf95*) # Portland Group f77 and f90 compilers + whole_archive_flag_spec_F77='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag -Mnomain' ;; + ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 + tmp_addflag=' -i_dynamic' ;; + efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 + tmp_addflag=' -i_dynamic -nofor_main' ;; + ifc* | ifort*) # Intel Fortran compiler + tmp_addflag=' -nofor_main' ;; + esac + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) # Sun C 5.9 + whole_archive_flag_spec_F77='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_sharedflag='-G' ;; + *Sun\ F*) # Sun Fortran 8.3 + tmp_sharedflag='-G' ;; + *) + tmp_sharedflag='-shared' ;; + esac + archive_cmds_F77='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + + if test $supports_anon_versioning = yes; then + archive_expsym_cmds_F77='$echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + $echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' + fi + else + ld_shlibs_F77=no + fi + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + archive_cmds_F77='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' + wlarc= + else + archive_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + fi + ;; + + solaris*) + if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then + ld_shlibs_F77=no + cat <&2 + +*** Warning: The releases 2.8.* of the GNU linker cannot reliably +*** create shared libraries on Solaris systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.9.1 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +EOF + elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + archive_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs_F77=no + fi + ;; + + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) + case `$LD -v 2>&1` in + *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) + ld_shlibs_F77=no + cat <<_LT_EOF 1>&2 + +*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not +*** reliably create shared libraries on SCO systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.16.91.0.3 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + ;; + *) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + hardcode_libdir_flag_spec_F77='`test -z "$SCOABSPATH" && echo ${wl}-rpath,$libdir`' + archive_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib' + archive_expsym_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname,\${SCOABSPATH:+${install_libdir}/}$soname,-retain-symbols-file,$export_symbols -o $lib' + else + ld_shlibs_F77=no + fi + ;; + esac + ;; + + sunos4*) + archive_cmds_F77='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' + wlarc= + hardcode_direct_F77=yes + hardcode_shlibpath_var_F77=no + ;; + + *) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + archive_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs_F77=no + fi + ;; + esac + + if test "$ld_shlibs_F77" = no; then + runpath_var= + hardcode_libdir_flag_spec_F77= + export_dynamic_flag_spec_F77= + whole_archive_flag_spec_F77= + fi + else + # PORTME fill in a description of your system's linker (not GNU ld) + case $host_os in + aix3*) + allow_undefined_flag_F77=unsupported + always_export_symbols_F77=yes + archive_expsym_cmds_F77='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + hardcode_minus_L_F77=yes + if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + hardcode_direct_F77=unsupported + fi + ;; + + aix[4-9]*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + if $NM -V 2>&1 | grep 'GNU' > /dev/null; then + export_symbols_cmds_F77='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols' + else + export_symbols_cmds_F77='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols' + fi + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) + for ld_flag in $LDFLAGS; do + if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then + aix_use_runtimelinking=yes + break + fi + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + archive_cmds_F77='' + hardcode_direct_F77=yes + hardcode_libdir_separator_F77=':' + link_all_deplibs_F77=yes + + if test "$GCC" = yes; then + case $host_os in aix4.[012]|aix4.[012].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && \ + strings "$collect2name" | grep resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + hardcode_direct_F77=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + hardcode_minus_L_F77=yes + hardcode_libdir_flag_spec_F77='-L$libdir' + hardcode_libdir_separator_F77= + fi + ;; + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to export. + always_export_symbols_F77=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + allow_undefined_flag_F77='-berok' + # Determine the default libpath from the value encoded in an empty executable. + cat >conftest.$ac_ext <<_ACEOF + program main + + end +_ACEOF +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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_f77_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + +lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\(.*\)$/\1/ + p + } + }' +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then + aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +fi +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + + hardcode_libdir_flag_spec_F77='${wl}-blibpath:$libdir:'"$aix_libpath" + archive_expsym_cmds_F77="\$CC"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + hardcode_libdir_flag_spec_F77='${wl}-R $libdir:/usr/lib:/lib' + allow_undefined_flag_F77="-z nodefs" + archive_expsym_cmds_F77="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an empty executable. + cat >conftest.$ac_ext <<_ACEOF + program main + + end +_ACEOF +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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_f77_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + +lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\(.*\)$/\1/ + p + } + }' +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then + aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +fi +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + + hardcode_libdir_flag_spec_F77='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + no_undefined_flag_F77=' ${wl}-bernotok' + allow_undefined_flag_F77=' ${wl}-berok' + # Exported symbols can be pulled into shared objects from archives + whole_archive_flag_spec_F77='$convenience' + archive_cmds_need_lc_F77=yes + # This is similar to how AIX traditionally builds its shared libraries. + archive_expsym_cmds_F77="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + amigaos*) + archive_cmds_F77='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec_F77='-L$libdir' + hardcode_minus_L_F77=yes + # see comment about different semantics on the GNU ld section + ld_shlibs_F77=no + ;; + + bsdi[45]*) + export_dynamic_flag_spec_F77=-rdynamic + ;; + + cygwin* | mingw* | pw32*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + hardcode_libdir_flag_spec_F77=' ' + allow_undefined_flag_F77=unsupported + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + archive_cmds_F77='$CC -o $lib $libobjs $compiler_flags `echo "$deplibs" | $SED -e '\''s/ -lc$//'\''` -link -dll~linknames=' + # The linker will automatically build a .lib file if we build a DLL. + old_archive_From_new_cmds_F77='true' + # FIXME: Should let the user specify the lib program. + old_archive_cmds_F77='lib -OUT:$oldlib$oldobjs$old_deplibs' + fix_srcfile_path_F77='`cygpath -w "$srcfile"`' + enable_shared_with_static_runtimes_F77=yes + ;; + + darwin* | rhapsody*) + case $host_os in + rhapsody* | darwin1.[012]) + allow_undefined_flag_F77='${wl}-undefined ${wl}suppress' + ;; + *) # Darwin 1.3 on + if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then + allow_undefined_flag_F77='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' + else + case ${MACOSX_DEPLOYMENT_TARGET} in + 10.[012]) + allow_undefined_flag_F77='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' + ;; + 10.*) + allow_undefined_flag_F77='${wl}-undefined ${wl}dynamic_lookup' + ;; + esac + fi + ;; + esac + archive_cmds_need_lc_F77=no + hardcode_direct_F77=no + hardcode_automatic_F77=yes + hardcode_shlibpath_var_F77=unsupported + whole_archive_flag_spec_F77='' + link_all_deplibs_F77=yes + if test "$GCC" = yes ; then + output_verbose_link_cmd='echo' + archive_cmds_F77="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" + module_cmds_F77="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" + archive_expsym_cmds_F77="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" + module_expsym_cmds_F77="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" + else + case $cc_basename in + xlc*) + output_verbose_link_cmd='echo' + archive_cmds_F77='$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}`echo $rpath/$soname` $xlcverstring' + module_cmds_F77='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' + # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds + archive_expsym_cmds_F77='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}$rpath/$soname $xlcverstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + module_expsym_cmds_F77='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + ;; + *) + ld_shlibs_F77=no + ;; + esac + fi + ;; + + dgux*) + archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec_F77='-L$libdir' + hardcode_shlibpath_var_F77=no + ;; + + freebsd1*) + ld_shlibs_F77=no + ;; + + # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor + # support. Future versions do this automatically, but an explicit c++rt0.o + # does not break anything, and helps significantly (at the cost of a little + # extra space). + freebsd2.2*) + archive_cmds_F77='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' + hardcode_libdir_flag_spec_F77='-R$libdir' + hardcode_direct_F77=yes + hardcode_shlibpath_var_F77=no + ;; + + # Unfortunately, older versions of FreeBSD 2 do not have this feature. + freebsd2*) + archive_cmds_F77='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct_F77=yes + hardcode_minus_L_F77=yes + hardcode_shlibpath_var_F77=no + ;; + + # FreeBSD 3 and greater uses gcc -shared to do shared libraries. + freebsd* | dragonfly*) + archive_cmds_F77='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec_F77='-R$libdir' + hardcode_direct_F77=yes + hardcode_shlibpath_var_F77=no + ;; + + hpux9*) + if test "$GCC" = yes; then + archive_cmds_F77='$rm $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + archive_cmds_F77='$rm $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + fi + hardcode_libdir_flag_spec_F77='${wl}+b ${wl}$libdir' + hardcode_libdir_separator_F77=: + hardcode_direct_F77=yes + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L_F77=yes + export_dynamic_flag_spec_F77='${wl}-E' + ;; + + hpux10*) + if test "$GCC" = yes -a "$with_gnu_ld" = no; then + archive_cmds_F77='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds_F77='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' + fi + if test "$with_gnu_ld" = no; then + hardcode_libdir_flag_spec_F77='${wl}+b ${wl}$libdir' + hardcode_libdir_separator_F77=: + + hardcode_direct_F77=yes + export_dynamic_flag_spec_F77='${wl}-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L_F77=yes + fi + ;; + + hpux11*) + if test "$GCC" = yes -a "$with_gnu_ld" = no; then + case $host_cpu in + hppa*64*) + archive_cmds_F77='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + archive_cmds_F77='$CC -shared ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + archive_cmds_F77='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + else + case $host_cpu in + hppa*64*) + archive_cmds_F77='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + archive_cmds_F77='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + archive_cmds_F77='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + fi + if test "$with_gnu_ld" = no; then + hardcode_libdir_flag_spec_F77='${wl}+b ${wl}$libdir' + hardcode_libdir_separator_F77=: + + case $host_cpu in + hppa*64*|ia64*) + hardcode_libdir_flag_spec_ld_F77='+b $libdir' + hardcode_direct_F77=no + hardcode_shlibpath_var_F77=no + ;; + *) + hardcode_direct_F77=yes + export_dynamic_flag_spec_F77='${wl}-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L_F77=yes + ;; + esac + fi + ;; + + irix5* | irix6* | nonstopux*) + if test "$GCC" = yes; then + archive_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + archive_cmds_F77='$LD -shared $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + hardcode_libdir_flag_spec_ld_F77='-rpath $libdir' + fi + hardcode_libdir_flag_spec_F77='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator_F77=: + link_all_deplibs_F77=yes + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + archive_cmds_F77='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out + else + archive_cmds_F77='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF + fi + hardcode_libdir_flag_spec_F77='-R$libdir' + hardcode_direct_F77=yes + hardcode_shlibpath_var_F77=no + ;; + + newsos6) + archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct_F77=yes + hardcode_libdir_flag_spec_F77='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator_F77=: + hardcode_shlibpath_var_F77=no + ;; + + openbsd*) + if test -f /usr/libexec/ld.so; then + hardcode_direct_F77=yes + hardcode_shlibpath_var_F77=no + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + archive_cmds_F77='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_F77='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' + hardcode_libdir_flag_spec_F77='${wl}-rpath,$libdir' + export_dynamic_flag_spec_F77='${wl}-E' + else + case $host_os in + openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) + archive_cmds_F77='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec_F77='-R$libdir' + ;; + *) + archive_cmds_F77='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec_F77='${wl}-rpath,$libdir' + ;; + esac + fi + else + ld_shlibs_F77=no + fi + ;; + + os2*) + hardcode_libdir_flag_spec_F77='-L$libdir' + hardcode_minus_L_F77=yes + allow_undefined_flag_F77=unsupported + archive_cmds_F77='$echo "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$echo DATA >> $output_objdir/$libname.def~$echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~$echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' + old_archive_From_new_cmds_F77='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' + ;; + + osf3*) + if test "$GCC" = yes; then + allow_undefined_flag_F77=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds_F77='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + allow_undefined_flag_F77=' -expect_unresolved \*' + archive_cmds_F77='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + fi + hardcode_libdir_flag_spec_F77='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator_F77=: + ;; + + osf4* | osf5*) # as osf3* with the addition of -msym flag + if test "$GCC" = yes; then + allow_undefined_flag_F77=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds_F77='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + hardcode_libdir_flag_spec_F77='${wl}-rpath ${wl}$libdir' + else + allow_undefined_flag_F77=' -expect_unresolved \*' + archive_cmds_F77='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + archive_expsym_cmds_F77='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; echo "-hidden">> $lib.exp~ + $LD -shared${allow_undefined_flag} -input $lib.exp $linker_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib~$rm $lib.exp' + + # Both c and cxx compiler support -rpath directly + hardcode_libdir_flag_spec_F77='-rpath $libdir' + fi + hardcode_libdir_separator_F77=: + ;; + + solaris*) + no_undefined_flag_F77=' -z text' + if test "$GCC" = yes; then + wlarc='${wl}' + archive_cmds_F77='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_F77='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -shared ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$rm $lib.exp' + else + wlarc='' + archive_cmds_F77='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' + archive_expsym_cmds_F77='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp' + fi + hardcode_libdir_flag_spec_F77='-R$libdir' + hardcode_shlibpath_var_F77=no + case $host_os in + solaris2.[0-5] | solaris2.[0-5].*) ;; + *) + # The compiler driver will combine and reorder linker options, + # but understands `-z linker_flag'. GCC discards it without `$wl', + # but is careful enough not to reorder. + # Supported since Solaris 2.6 (maybe 2.5.1?) + if test "$GCC" = yes; then + whole_archive_flag_spec_F77='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' + else + whole_archive_flag_spec_F77='-z allextract$convenience -z defaultextract' + fi + ;; + esac + link_all_deplibs_F77=yes + ;; + + sunos4*) + if test "x$host_vendor" = xsequent; then + # Use $CC to link under sequent, because it throws in some extra .o + # files that make .init and .fini sections work. + archive_cmds_F77='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds_F77='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' + fi + hardcode_libdir_flag_spec_F77='-L$libdir' + hardcode_direct_F77=yes + hardcode_minus_L_F77=yes + hardcode_shlibpath_var_F77=no + ;; + + sysv4) + case $host_vendor in + sni) + archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct_F77=yes # is this really true??? + ;; + siemens) + ## LD is ld it makes a PLAMLIB + ## CC just makes a GrossModule. + archive_cmds_F77='$LD -G -o $lib $libobjs $deplibs $linker_flags' + reload_cmds_F77='$CC -r -o $output$reload_objs' + hardcode_direct_F77=no + ;; + motorola) + archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct_F77=no #Motorola manual says yes, but my tests say they lie + ;; + esac + runpath_var='LD_RUN_PATH' + hardcode_shlibpath_var_F77=no + ;; + + sysv4.3*) + archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var_F77=no + export_dynamic_flag_spec_F77='-Bexport' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var_F77=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + ld_shlibs_F77=yes + fi + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) + no_undefined_flag_F77='${wl}-z,text' + archive_cmds_need_lc_F77=no + hardcode_shlibpath_var_F77=no + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + archive_cmds_F77='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_F77='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds_F77='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_F77='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + no_undefined_flag_F77='${wl}-z,text' + allow_undefined_flag_F77='${wl}-z,nodefs' + archive_cmds_need_lc_F77=no + hardcode_shlibpath_var_F77=no + hardcode_libdir_flag_spec_F77='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`' + hardcode_libdir_separator_F77=':' + link_all_deplibs_F77=yes + export_dynamic_flag_spec_F77='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + archive_cmds_F77='$CC -shared ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_F77='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds_F77='$CC -G ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_F77='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + uts4*) + archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec_F77='-L$libdir' + hardcode_shlibpath_var_F77=no + ;; + + *) + ld_shlibs_F77=no + ;; + esac + fi + +{ echo "$as_me:$LINENO: result: $ld_shlibs_F77" >&5 +echo "${ECHO_T}$ld_shlibs_F77" >&6; } +test "$ld_shlibs_F77" = no && can_build_shared=no + +# +# Do we need to explicitly link libc? +# +case "x$archive_cmds_need_lc_F77" in +x|xyes) + # Assume -lc should be added + archive_cmds_need_lc_F77=yes + + if test "$enable_shared" = yes && test "$GCC" = yes; then + case $archive_cmds_F77 in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + { echo "$as_me:$LINENO: checking whether -lc should be explicitly linked in" >&5 +echo $ECHO_N "checking whether -lc should be explicitly linked in... $ECHO_C" >&6; } + $rm conftest* + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$lt_prog_compiler_wl_F77 + pic_flag=$lt_prog_compiler_pic_F77 + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$allow_undefined_flag_F77 + allow_undefined_flag_F77= + if { (eval echo "$as_me:$LINENO: \"$archive_cmds_F77 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1\"") >&5 + (eval $archive_cmds_F77 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + then + archive_cmds_need_lc_F77=no + else + archive_cmds_need_lc_F77=yes + fi + allow_undefined_flag_F77=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $rm conftest* + { echo "$as_me:$LINENO: result: $archive_cmds_need_lc_F77" >&5 +echo "${ECHO_T}$archive_cmds_need_lc_F77" >&6; } + ;; + esac + fi + ;; +esac + +{ echo "$as_me:$LINENO: checking dynamic linker characteristics" >&5 +echo $ECHO_N "checking dynamic linker characteristics... $ECHO_C" >&6; } +library_names_spec= +libname_spec='lib$name' +soname_spec= +shrext_cmds=".so" +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" + +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + +case $host_os in +aix3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='${libname}${release}${shared_ext}$major' + ;; + +aix[4-9]*) + version_type=linux + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test "$host_cpu" = ia64; then + # AIX 5 supports IA64 + library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line `#! .'. This would cause the generated library to + # depend on `.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[01] | aix4.[01].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # AIX (on Power*) has no versioning support, so currently we can not hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + if test "$aix_use_runtimelinking" = yes; then + # If using run time linking (on AIX 4.2 or later) use lib.so + # instead of lib.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + else + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='${libname}${release}.a $libname.a' + soname_spec='${libname}${release}${shared_ext}$major' + fi + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' + ;; + +beos*) + library_names_spec='${libname}${shared_ext}' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi[45]*) + version_type=linux + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32*) + version_type=windows + shrext_cmds=".dll" + need_version=no + need_lib_prefix=no + + case $GCC,$host_os in + yes,cygwin* | yes,mingw* | yes,pw32*) + library_names_spec='$libname.dll.a' + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i;echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $rm \$dlpath' + shlibpath_overrides_runpath=yes + + case $host_os in + cygwin*) + # Cygwin DLLs use 'cyg' prefix rather than 'lib' + soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib" + ;; + mingw*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if echo "$sys_lib_search_path_spec" | grep ';[c-zC-Z]:/' >/dev/null; then + # It is most probably a Windows format PATH printed by + # mingw gcc, but we are running on Cygwin. Gcc prints its search + # path with ; separators, and with drive letters. We can handle the + # drive letters (cygwin fileutils understands them), so leave them, + # especially as we might pass files found there to a mingw objdump, + # which wouldn't understand a cygwinified path. Ahh. + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + ;; + pw32*) + # pw32 DLLs use 'pw' prefix rather than 'lib' + library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + ;; + esac + ;; + + *) + library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' + ;; + esac + dynamic_linker='Win32 ld.exe' + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${versuffix}$shared_ext ${libname}${release}${major}$shared_ext ${libname}$shared_ext' + soname_spec='${libname}${release}${major}$shared_ext' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' + + sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd1*) + dynamic_linker=no + ;; + +freebsd* | dragonfly*) + # DragonFly does not have aout. When/if they implement a new + # versioning mechanism, adjust this. + if test -x /usr/bin/objformat; then + objformat=`/usr/bin/objformat` + else + case $host_os in + freebsd[123]*) objformat=aout ;; + *) objformat=elf ;; + esac + fi + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[01]* | freebsdelf3.[01]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ + freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + *) # from 4.6 on, and DragonFly + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + esac + ;; + +gnu*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + case $host_cpu in + ia64*) + shrext_cmds='.so' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + if test "X$HPUX_IA64_MODE" = X32; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + fi + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + hppa*64*) + shrext_cmds='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) + shrext_cmds='.sl' + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + ;; + esac + # HP-UX runs *really* slowly unless shared libraries are mode 555. + postinstall_cmds='chmod 555 $lib' + ;; + +interix[3-9]*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) + if test "$lt_cv_prog_gnu_ld" = yes; then + version_type=linux + else + version_type=irix + fi ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") + libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") + libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") + libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" + sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" + hardcode_into_libs=yes + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +# This must be Linux ELF. +linux* | k*bsd*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # Append ld.so.conf contents to the search path + if test -f /etc/ld.so.conf; then + lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '` + sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" + fi + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +nto-qnx*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +openbsd*) + version_type=sunos + sys_lib_dlsearch_path_spec="/usr/lib" + need_lib_prefix=no + # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. + case $host_os in + openbsd3.3 | openbsd3.3.*) need_version=yes ;; + *) need_version=no ;; + esac + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + case $host_os in + openbsd2.[89] | openbsd2.[89].*) + shlibpath_overrides_runpath=no + ;; + *) + shlibpath_overrides_runpath=yes + ;; + esac + else + shlibpath_overrides_runpath=yes + fi + ;; + +os2*) + libname_spec='$name' + shrext_cmds=".dll" + need_lib_prefix=no + library_names_spec='$libname${shared_ext} $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + ;; + +rdos*) + dynamic_linker=no + ;; + +solaris*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + export_dynamic_flag_spec='${wl}-Blargedynsym' + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec ;then + version_type=linux + library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' + soname_spec='$libname${shared_ext}.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + version_type=freebsd-elf + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + if test "$with_gnu_ld" = yes; then + sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' + shlibpath_overrides_runpath=no + else + sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' + shlibpath_overrides_runpath=yes + case $host_os in + sco3.2v5*) + sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" + ;; + esac + fi + sys_lib_dlsearch_path_spec='/usr/lib' + ;; + +uts4*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +{ echo "$as_me:$LINENO: result: $dynamic_linker" >&5 +echo "${ECHO_T}$dynamic_linker" >&6; } +test "$dynamic_linker" = no && can_build_shared=no + +if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_cv_sys_lib_search_path_spec="$sys_lib_search_path_spec" +fi + +sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" +if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_cv_sys_lib_dlsearch_path_spec="$sys_lib_dlsearch_path_spec" +fi + +sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test "$GCC" = yes; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +{ echo "$as_me:$LINENO: checking how to hardcode library paths into programs" >&5 +echo $ECHO_N "checking how to hardcode library paths into programs... $ECHO_C" >&6; } +hardcode_action_F77= +if test -n "$hardcode_libdir_flag_spec_F77" || \ + test -n "$runpath_var_F77" || \ + test "X$hardcode_automatic_F77" = "Xyes" ; then + + # We can hardcode non-existant directories. + if test "$hardcode_direct_F77" != no && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test "$_LT_AC_TAGVAR(hardcode_shlibpath_var, F77)" != no && + test "$hardcode_minus_L_F77" != no; then + # Linking always hardcodes the temporary library directory. + hardcode_action_F77=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + hardcode_action_F77=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + hardcode_action_F77=unsupported +fi +{ echo "$as_me:$LINENO: result: $hardcode_action_F77" >&5 +echo "${ECHO_T}$hardcode_action_F77" >&6; } + +if test "$hardcode_action_F77" = relink; then + # Fast installation is not supported + enable_fast_install=no +elif test "$shlibpath_overrides_runpath" = yes || + test "$enable_shared" = no; then + # Fast installation is not necessary + enable_fast_install=needless +fi + + +# The else clause should only fire when bootstrapping the +# libtool distribution, otherwise you forgot to ship ltmain.sh +# with your package, and you will get complaints that there are +# no rules to generate ltmain.sh. +if test -f "$ltmain"; then + # See if we are running on zsh, and set the options which allow our commands through + # without removal of \ escapes. + if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST + fi + # Now quote all the things that may contain metacharacters while being + # careful not to overquote the AC_SUBSTed values. We take copies of the + # variables and quote the copies for generation of the libtool script. + for var in echo old_CC old_CFLAGS AR AR_FLAGS EGREP RANLIB LN_S LTCC LTCFLAGS NM \ + SED SHELL STRIP \ + libname_spec library_names_spec soname_spec extract_expsyms_cmds \ + old_striplib striplib file_magic_cmd finish_cmds finish_eval \ + deplibs_check_method reload_flag reload_cmds need_locks \ + lt_cv_sys_global_symbol_pipe lt_cv_sys_global_symbol_to_cdecl \ + lt_cv_sys_global_symbol_to_c_name_address \ + sys_lib_search_path_spec sys_lib_dlsearch_path_spec \ + old_postinstall_cmds old_postuninstall_cmds \ + compiler_F77 \ + CC_F77 \ + LD_F77 \ + lt_prog_compiler_wl_F77 \ + lt_prog_compiler_pic_F77 \ + lt_prog_compiler_static_F77 \ + lt_prog_compiler_no_builtin_flag_F77 \ + export_dynamic_flag_spec_F77 \ + thread_safe_flag_spec_F77 \ + whole_archive_flag_spec_F77 \ + enable_shared_with_static_runtimes_F77 \ + old_archive_cmds_F77 \ + old_archive_from_new_cmds_F77 \ + predep_objects_F77 \ + postdep_objects_F77 \ + predeps_F77 \ + postdeps_F77 \ + compiler_lib_search_path_F77 \ + compiler_lib_search_dirs_F77 \ + archive_cmds_F77 \ + archive_expsym_cmds_F77 \ + postinstall_cmds_F77 \ + postuninstall_cmds_F77 \ + old_archive_from_expsyms_cmds_F77 \ + allow_undefined_flag_F77 \ + no_undefined_flag_F77 \ + export_symbols_cmds_F77 \ + hardcode_libdir_flag_spec_F77 \ + hardcode_libdir_flag_spec_ld_F77 \ + hardcode_libdir_separator_F77 \ + hardcode_automatic_F77 \ + module_cmds_F77 \ + module_expsym_cmds_F77 \ + lt_cv_prog_compiler_c_o_F77 \ + fix_srcfile_path_F77 \ + exclude_expsyms_F77 \ + include_expsyms_F77; do + + case $var in + old_archive_cmds_F77 | \ + old_archive_from_new_cmds_F77 | \ + archive_cmds_F77 | \ + archive_expsym_cmds_F77 | \ + module_cmds_F77 | \ + module_expsym_cmds_F77 | \ + old_archive_from_expsyms_cmds_F77 | \ + export_symbols_cmds_F77 | \ + extract_expsyms_cmds | reload_cmds | finish_cmds | \ + postinstall_cmds | postuninstall_cmds | \ + old_postinstall_cmds | old_postuninstall_cmds | \ + sys_lib_search_path_spec | sys_lib_dlsearch_path_spec) + # Double-quote double-evaled strings. + eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\"" + ;; + *) + eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\"" + ;; + esac + done + + case $lt_echo in + *'\$0 --fallback-echo"') + lt_echo=`$echo "X$lt_echo" | $Xsed -e 's/\\\\\\\$0 --fallback-echo"$/$0 --fallback-echo"/'` + ;; + esac + +cfgfile="$ofile" + + cat <<__EOF__ >> "$cfgfile" +# ### BEGIN LIBTOOL TAG CONFIG: $tagname + +# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: + +# Shell to use when invoking shell scripts. +SHELL=$lt_SHELL + +# Whether or not to build shared libraries. +build_libtool_libs=$enable_shared + +# Whether or not to build static libraries. +build_old_libs=$enable_static + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=$archive_cmds_need_lc_F77 + +# Whether or not to disallow shared libs when runtime libs are static +allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_F77 + +# Whether or not to optimize for fast installation. +fast_install=$enable_fast_install + +# The host system. +host_alias=$host_alias +host=$host +host_os=$host_os + +# The build system. +build_alias=$build_alias +build=$build +build_os=$build_os + +# An echo program that does not interpret backslashes. +echo=$lt_echo + +# The archiver. +AR=$lt_AR +AR_FLAGS=$lt_AR_FLAGS + +# A C compiler. +LTCC=$lt_LTCC + +# LTCC compiler flags. +LTCFLAGS=$lt_LTCFLAGS + +# A language-specific compiler. +CC=$lt_compiler_F77 + +# Is the compiler the GNU C compiler? +with_gcc=$GCC_F77 + +# An ERE matcher. +EGREP=$lt_EGREP + +# The linker used to build libraries. +LD=$lt_LD_F77 + +# Whether we need hard or soft links. +LN_S=$lt_LN_S + +# A BSD-compatible nm program. +NM=$lt_NM + +# A symbol stripping program +STRIP=$lt_STRIP + +# Used to examine libraries when file_magic_cmd begins "file" +MAGIC_CMD=$MAGIC_CMD + +# Used on cygwin: DLL creation program. +DLLTOOL="$DLLTOOL" + +# Used on cygwin: object dumper. +OBJDUMP="$OBJDUMP" + +# Used on cygwin: assembler. +AS="$AS" + +# The name of the directory that contains temporary libtool files. +objdir=$objdir + +# How to create reloadable object files. +reload_flag=$lt_reload_flag +reload_cmds=$lt_reload_cmds + +# How to pass a linker flag through the compiler. +wl=$lt_lt_prog_compiler_wl_F77 + +# Object file suffix (normally "o"). +objext="$ac_objext" + +# Old archive suffix (normally "a"). +libext="$libext" + +# Shared library suffix (normally ".so"). +shrext_cmds='$shrext_cmds' + +# Executable file suffix (normally ""). +exeext="$exeext" + +# Additional compiler flags for building library objects. +pic_flag=$lt_lt_prog_compiler_pic_F77 +pic_mode=$pic_mode + +# What is the maximum length of a command? +max_cmd_len=$lt_cv_sys_max_cmd_len + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$lt_lt_cv_prog_compiler_c_o_F77 + +# Must we lock files when doing compilation? +need_locks=$lt_need_locks + +# Do we need the lib prefix for modules? +need_lib_prefix=$need_lib_prefix + +# Do we need a version for libraries? +need_version=$need_version + +# Whether dlopen is supported. +dlopen_support=$enable_dlopen + +# Whether dlopen of programs is supported. +dlopen_self=$enable_dlopen_self + +# Whether dlopen of statically linked programs is supported. +dlopen_self_static=$enable_dlopen_self_static + +# Compiler flag to prevent dynamic linking. +link_static_flag=$lt_lt_prog_compiler_static_F77 + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_F77 + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_F77 + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec=$lt_whole_archive_flag_spec_F77 + +# Compiler flag to generate thread-safe objects. +thread_safe_flag_spec=$lt_thread_safe_flag_spec_F77 + +# Library versioning type. +version_type=$version_type + +# Format of library name prefix. +libname_spec=$lt_libname_spec + +# List of archive names. First name is the real one, the rest are links. +# The last name is the one that the linker finds with -lNAME. +library_names_spec=$lt_library_names_spec + +# The coded name of the library, if different from the real name. +soname_spec=$lt_soname_spec + +# Commands used to build and install an old-style archive. +RANLIB=$lt_RANLIB +old_archive_cmds=$lt_old_archive_cmds_F77 +old_postinstall_cmds=$lt_old_postinstall_cmds +old_postuninstall_cmds=$lt_old_postuninstall_cmds + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_F77 + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_F77 + +# Commands used to build and install a shared archive. +archive_cmds=$lt_archive_cmds_F77 +archive_expsym_cmds=$lt_archive_expsym_cmds_F77 +postinstall_cmds=$lt_postinstall_cmds +postuninstall_cmds=$lt_postuninstall_cmds + +# Commands used to build a loadable module (assumed same as above if empty) +module_cmds=$lt_module_cmds_F77 +module_expsym_cmds=$lt_module_expsym_cmds_F77 + +# Commands to strip libraries. +old_striplib=$lt_old_striplib +striplib=$lt_striplib + +# Dependencies to place before the objects being linked to create a +# shared library. +predep_objects=$lt_predep_objects_F77 + +# Dependencies to place after the objects being linked to create a +# shared library. +postdep_objects=$lt_postdep_objects_F77 + +# Dependencies to place before the objects being linked to create a +# shared library. +predeps=$lt_predeps_F77 + +# Dependencies to place after the objects being linked to create a +# shared library. +postdeps=$lt_postdeps_F77 + +# The directories searched by this compiler when creating a shared +# library +compiler_lib_search_dirs=$lt_compiler_lib_search_dirs_F77 + +# The library search path used internally by the compiler when linking +# a shared library. +compiler_lib_search_path=$lt_compiler_lib_search_path_F77 + +# Method to check whether dependent libraries are shared objects. +deplibs_check_method=$lt_deplibs_check_method + +# Command to use when deplibs_check_method == file_magic. +file_magic_cmd=$lt_file_magic_cmd + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$lt_allow_undefined_flag_F77 + +# Flag that forces no undefined symbols. +no_undefined_flag=$lt_no_undefined_flag_F77 + +# Commands used to finish a libtool library installation in a directory. +finish_cmds=$lt_finish_cmds + +# Same as above, but a single script fragment to be evaled but not shown. +finish_eval=$lt_finish_eval + +# Take the output of nm and produce a listing of raw symbols and C names. +global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe + +# Transform the output of nm in a proper C declaration +global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl + +# Transform the output of nm in a C name address pair +global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address + +# This is the shared library runtime path variable. +runpath_var=$runpath_var + +# This is the shared library path variable. +shlibpath_var=$shlibpath_var + +# Is shlibpath searched before the hard-coded library search path? +shlibpath_overrides_runpath=$shlibpath_overrides_runpath + +# How to hardcode a shared library path into an executable. +hardcode_action=$hardcode_action_F77 + +# Whether we should hardcode library paths into libraries. +hardcode_into_libs=$hardcode_into_libs + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist. +hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_F77 + +# If ld is used when linking, flag to hardcode \$libdir into +# a binary during linking. This must work even if \$libdir does +# not exist. +hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld_F77 + +# Whether we need a single -rpath flag with a separated argument. +hardcode_libdir_separator=$lt_hardcode_libdir_separator_F77 + +# Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the +# resulting binary. +hardcode_direct=$hardcode_direct_F77 + +# Set to yes if using the -LDIR flag during linking hardcodes DIR into the +# resulting binary. +hardcode_minus_L=$hardcode_minus_L_F77 + +# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into +# the resulting binary. +hardcode_shlibpath_var=$hardcode_shlibpath_var_F77 + +# Set to yes if building a shared library automatically hardcodes DIR into the library +# and all subsequent libraries and executables linked against it. +hardcode_automatic=$hardcode_automatic_F77 + +# Variables whose values should be saved in libtool wrapper scripts and +# restored at relink time. +variables_saved_for_relink="$variables_saved_for_relink" + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=$link_all_deplibs_F77 + +# Compile-time system search path for libraries +sys_lib_search_path_spec=$lt_sys_lib_search_path_spec + +# Run-time system search path for libraries +sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec + +# Fix the shell variable \$srcfile for the compiler. +fix_srcfile_path=$lt_fix_srcfile_path + +# Set to yes if exported symbols are required. +always_export_symbols=$always_export_symbols_F77 + +# The commands to list exported symbols. +export_symbols_cmds=$lt_export_symbols_cmds_F77 + +# The commands to extract the exported symbol list from a shared archive. +extract_expsyms_cmds=$lt_extract_expsyms_cmds + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms=$lt_exclude_expsyms_F77 + +# Symbols that must always be exported. +include_expsyms=$lt_include_expsyms_F77 + +# ### END LIBTOOL TAG CONFIG: $tagname + +__EOF__ + + +else + # If there is no Makefile yet, we rely on a make rule to execute + # `config.status --recheck' to rerun these tests and create the + # libtool script then. + ltmain_in=`echo $ltmain | sed -e 's/\.sh$/.in/'` + if test -f "$ltmain_in"; then + test -f Makefile && make "$ltmain" + 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 + +CC="$lt_save_CC" + + else + tagname="" + fi + ;; + + GCJ) + if test -n "$GCJ" && test "X$GCJ" != "Xno"; then + + +# Source file extension for Java test sources. +ac_ext=java + +# Object file extension for compiled Java test sources. +objext=o +objext_GCJ=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="class foo {}" + +# Code to be used in simple link tests +lt_simple_link_test_code='public class conftest { public static void main(String[] argv) {}; }' + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC + + +# save warnings/boilerplate of simple test code +ac_outfile=conftest.$ac_objext +echo "$lt_simple_compile_test_code" >conftest.$ac_ext +eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_compiler_boilerplate=`cat conftest.err` +$rm conftest* + +ac_outfile=conftest.$ac_objext +echo "$lt_simple_link_test_code" >conftest.$ac_ext +eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_linker_boilerplate=`cat conftest.err` +$rm -r conftest* + + +# Allow CC to be a program name with arguments. +lt_save_CC="$CC" +CC=${GCJ-"gcj"} +compiler=$CC +compiler_GCJ=$CC +for cc_temp in $compiler""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`$echo "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"` + + +# GCJ did not exist at the time GCC didn't implicitly link libc in. +archive_cmds_need_lc_GCJ=no + +old_archive_cmds_GCJ=$old_archive_cmds + + +lt_prog_compiler_no_builtin_flag_GCJ= + +if test "$GCC" = yes; then + lt_prog_compiler_no_builtin_flag_GCJ=' -fno-builtin' + + +{ echo "$as_me:$LINENO: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 +echo $ECHO_N "checking if $compiler supports -fno-rtti -fno-exceptions... $ECHO_C" >&6; } +if test "${lt_cv_prog_compiler_rtti_exceptions+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_cv_prog_compiler_rtti_exceptions=no + ac_outfile=conftest.$ac_objext + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="-fno-rtti -fno-exceptions" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:16835: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:16839: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_rtti_exceptions=yes + fi + fi + $rm conftest* + +fi +{ echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_rtti_exceptions" >&5 +echo "${ECHO_T}$lt_cv_prog_compiler_rtti_exceptions" >&6; } + +if test x"$lt_cv_prog_compiler_rtti_exceptions" = xyes; then + lt_prog_compiler_no_builtin_flag_GCJ="$lt_prog_compiler_no_builtin_flag_GCJ -fno-rtti -fno-exceptions" +else + : +fi + +fi + +lt_prog_compiler_wl_GCJ= +lt_prog_compiler_pic_GCJ= +lt_prog_compiler_static_GCJ= + +{ echo "$as_me:$LINENO: checking for $compiler option to produce PIC" >&5 +echo $ECHO_N "checking for $compiler option to produce PIC... $ECHO_C" >&6; } + + if test "$GCC" = yes; then + lt_prog_compiler_wl_GCJ='-Wl,' + lt_prog_compiler_static_GCJ='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static_GCJ='-Bstatic' + fi + ;; + + amigaos*) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + lt_prog_compiler_pic_GCJ='-m68020 -resident32 -malways-restore-a4' + ;; + + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + + mingw* | cygwin* | pw32* | os2*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + # Although the cygwin gcc ignores -fPIC, still need this for old-style + # (--disable-auto-import) libraries + + ;; + + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + lt_prog_compiler_pic_GCJ='-fno-common' + ;; + + interix[3-9]*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + + msdosdjgpp*) + # Just because we use GCC doesn't mean we suddenly get shared libraries + # on systems that don't support them. + lt_prog_compiler_can_build_shared_GCJ=no + enable_shared=no + ;; + + sysv4*MP*) + if test -d /usr/nec; then + lt_prog_compiler_pic_GCJ=-Kconform_pic + fi + ;; + + hpux*) + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic_GCJ='-fPIC' + ;; + esac + ;; + + *) + lt_prog_compiler_pic_GCJ='-fPIC' + ;; + esac + else + # PORTME Check for flag to pass linker flags through the system compiler. + case $host_os in + aix*) + lt_prog_compiler_wl_GCJ='-Wl,' + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static_GCJ='-Bstatic' + else + lt_prog_compiler_static_GCJ='-bnso -bI:/lib/syscalls.exp' + fi + ;; + darwin*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + case $cc_basename in + xlc*) + lt_prog_compiler_pic_GCJ='-qnocommon' + lt_prog_compiler_wl_GCJ='-Wl,' + ;; + esac + ;; + + mingw* | cygwin* | pw32* | os2*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + + ;; + + hpux9* | hpux10* | hpux11*) + lt_prog_compiler_wl_GCJ='-Wl,' + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic_GCJ='+Z' + ;; + esac + # Is there a better lt_prog_compiler_static that works with the bundled CC? + lt_prog_compiler_static_GCJ='${wl}-a ${wl}archive' + ;; + + irix5* | irix6* | nonstopux*) + lt_prog_compiler_wl_GCJ='-Wl,' + # PIC (with -KPIC) is the default. + lt_prog_compiler_static_GCJ='-non_shared' + ;; + + newsos6) + lt_prog_compiler_pic_GCJ='-KPIC' + lt_prog_compiler_static_GCJ='-Bstatic' + ;; + + linux* | k*bsd*-gnu) + case $cc_basename in + icc* | ecc*) + lt_prog_compiler_wl_GCJ='-Wl,' + lt_prog_compiler_pic_GCJ='-KPIC' + lt_prog_compiler_static_GCJ='-static' + ;; + pgcc* | pgf77* | pgf90* | pgf95*) + # Portland Group compilers (*not* the Pentium gcc compiler, + # which looks to be a dead project) + lt_prog_compiler_wl_GCJ='-Wl,' + lt_prog_compiler_pic_GCJ='-fpic' + lt_prog_compiler_static_GCJ='-Bstatic' + ;; + ccc*) + lt_prog_compiler_wl_GCJ='-Wl,' + # All Alpha code is PIC. + lt_prog_compiler_static_GCJ='-non_shared' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C 5.9 + lt_prog_compiler_pic_GCJ='-KPIC' + lt_prog_compiler_static_GCJ='-Bstatic' + lt_prog_compiler_wl_GCJ='-Wl,' + ;; + *Sun\ F*) + # Sun Fortran 8.3 passes all unrecognized flags to the linker + lt_prog_compiler_pic_GCJ='-KPIC' + lt_prog_compiler_static_GCJ='-Bstatic' + lt_prog_compiler_wl_GCJ='' + ;; + esac + ;; + esac + ;; + + osf3* | osf4* | osf5*) + lt_prog_compiler_wl_GCJ='-Wl,' + # All OSF/1 code is PIC. + lt_prog_compiler_static_GCJ='-non_shared' + ;; + + rdos*) + lt_prog_compiler_static_GCJ='-non_shared' + ;; + + solaris*) + lt_prog_compiler_pic_GCJ='-KPIC' + lt_prog_compiler_static_GCJ='-Bstatic' + case $cc_basename in + f77* | f90* | f95*) + lt_prog_compiler_wl_GCJ='-Qoption ld ';; + *) + lt_prog_compiler_wl_GCJ='-Wl,';; + esac + ;; + + sunos4*) + lt_prog_compiler_wl_GCJ='-Qoption ld ' + lt_prog_compiler_pic_GCJ='-PIC' + lt_prog_compiler_static_GCJ='-Bstatic' + ;; + + sysv4 | sysv4.2uw2* | sysv4.3*) + lt_prog_compiler_wl_GCJ='-Wl,' + lt_prog_compiler_pic_GCJ='-KPIC' + lt_prog_compiler_static_GCJ='-Bstatic' + ;; + + sysv4*MP*) + if test -d /usr/nec ;then + lt_prog_compiler_pic_GCJ='-Kconform_pic' + lt_prog_compiler_static_GCJ='-Bstatic' + fi + ;; + + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + lt_prog_compiler_wl_GCJ='-Wl,' + lt_prog_compiler_pic_GCJ='-KPIC' + lt_prog_compiler_static_GCJ='-Bstatic' + ;; + + unicos*) + lt_prog_compiler_wl_GCJ='-Wl,' + lt_prog_compiler_can_build_shared_GCJ=no + ;; + + uts4*) + lt_prog_compiler_pic_GCJ='-pic' + lt_prog_compiler_static_GCJ='-Bstatic' + ;; + + *) + lt_prog_compiler_can_build_shared_GCJ=no + ;; + esac + fi + +{ echo "$as_me:$LINENO: result: $lt_prog_compiler_pic_GCJ" >&5 +echo "${ECHO_T}$lt_prog_compiler_pic_GCJ" >&6; } + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$lt_prog_compiler_pic_GCJ"; then + +{ echo "$as_me:$LINENO: checking if $compiler PIC flag $lt_prog_compiler_pic_GCJ works" >&5 +echo $ECHO_N "checking if $compiler PIC flag $lt_prog_compiler_pic_GCJ works... $ECHO_C" >&6; } +if test "${lt_cv_prog_compiler_pic_works_GCJ+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_cv_prog_compiler_pic_works_GCJ=no + ac_outfile=conftest.$ac_objext + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$lt_prog_compiler_pic_GCJ" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:17125: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:17129: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_pic_works_GCJ=yes + fi + fi + $rm conftest* + +fi +{ echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_pic_works_GCJ" >&5 +echo "${ECHO_T}$lt_cv_prog_compiler_pic_works_GCJ" >&6; } + +if test x"$lt_cv_prog_compiler_pic_works_GCJ" = xyes; then + case $lt_prog_compiler_pic_GCJ in + "" | " "*) ;; + *) lt_prog_compiler_pic_GCJ=" $lt_prog_compiler_pic_GCJ" ;; + esac +else + lt_prog_compiler_pic_GCJ= + lt_prog_compiler_can_build_shared_GCJ=no +fi + +fi +case $host_os in + # For platforms which do not support PIC, -DPIC is meaningless: + *djgpp*) + lt_prog_compiler_pic_GCJ= + ;; + *) + lt_prog_compiler_pic_GCJ="$lt_prog_compiler_pic_GCJ" + ;; +esac + +# +# Check to make sure the static flag actually works. +# +wl=$lt_prog_compiler_wl_GCJ eval lt_tmp_static_flag=\"$lt_prog_compiler_static_GCJ\" +{ echo "$as_me:$LINENO: checking if $compiler static flag $lt_tmp_static_flag works" >&5 +echo $ECHO_N "checking if $compiler static flag $lt_tmp_static_flag works... $ECHO_C" >&6; } +if test "${lt_cv_prog_compiler_static_works_GCJ+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_cv_prog_compiler_static_works_GCJ=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $lt_tmp_static_flag" + echo "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&5 + $echo "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_static_works_GCJ=yes + fi + else + lt_cv_prog_compiler_static_works_GCJ=yes + fi + fi + $rm -r conftest* + LDFLAGS="$save_LDFLAGS" + +fi +{ echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_static_works_GCJ" >&5 +echo "${ECHO_T}$lt_cv_prog_compiler_static_works_GCJ" >&6; } + +if test x"$lt_cv_prog_compiler_static_works_GCJ" = xyes; then + : +else + lt_prog_compiler_static_GCJ= +fi + + +{ echo "$as_me:$LINENO: checking if $compiler supports -c -o file.$ac_objext" >&5 +echo $ECHO_N "checking if $compiler supports -c -o file.$ac_objext... $ECHO_C" >&6; } +if test "${lt_cv_prog_compiler_c_o_GCJ+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_cv_prog_compiler_c_o_GCJ=no + $rm -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:17229: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:17233: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + lt_cv_prog_compiler_c_o_GCJ=yes + fi + fi + chmod u+w . 2>&5 + $rm conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $rm out/ii_files/* && rmdir out/ii_files + $rm out/* && rmdir out + cd .. + rmdir conftest + $rm conftest* + +fi +{ echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_c_o_GCJ" >&5 +echo "${ECHO_T}$lt_cv_prog_compiler_c_o_GCJ" >&6; } + + +hard_links="nottested" +if test "$lt_cv_prog_compiler_c_o_GCJ" = no && test "$need_locks" != no; then + # do not overwrite the value of need_locks provided by the user + { echo "$as_me:$LINENO: checking if we can lock with hard links" >&5 +echo $ECHO_N "checking if we can lock with hard links... $ECHO_C" >&6; } + hard_links=yes + $rm conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + { echo "$as_me:$LINENO: result: $hard_links" >&5 +echo "${ECHO_T}$hard_links" >&6; } + if test "$hard_links" = no; then + { echo "$as_me:$LINENO: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 +echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} + need_locks=warn + fi +else + need_locks=no +fi + +{ echo "$as_me:$LINENO: checking whether the $compiler linker ($LD) supports shared libraries" >&5 +echo $ECHO_N "checking whether the $compiler linker ($LD) supports shared libraries... $ECHO_C" >&6; } + + runpath_var= + allow_undefined_flag_GCJ= + enable_shared_with_static_runtimes_GCJ=no + archive_cmds_GCJ= + archive_expsym_cmds_GCJ= + old_archive_From_new_cmds_GCJ= + old_archive_from_expsyms_cmds_GCJ= + export_dynamic_flag_spec_GCJ= + whole_archive_flag_spec_GCJ= + thread_safe_flag_spec_GCJ= + hardcode_libdir_flag_spec_GCJ= + hardcode_libdir_flag_spec_ld_GCJ= + hardcode_libdir_separator_GCJ= + hardcode_direct_GCJ=no + hardcode_minus_L_GCJ=no + hardcode_shlibpath_var_GCJ=unsupported + link_all_deplibs_GCJ=unknown + hardcode_automatic_GCJ=no + module_cmds_GCJ= + module_expsym_cmds_GCJ= + always_export_symbols_GCJ=no + export_symbols_cmds_GCJ='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + # include_expsyms should be a list of space-separated symbols to be *always* + # included in the symbol list + include_expsyms_GCJ= + # exclude_expsyms can be an extended regexp of symbols to exclude + # it will be wrapped by ` (' and `)$', so one must not match beginning or + # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', + # as well as any symbol that contains `d'. + exclude_expsyms_GCJ='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*' + # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out + # platforms (ab)use it in PIC code, but their linkers get confused if + # the symbol is explicitly referenced. Since portable code cannot + # rely on this symbol name, it's probably fine to never include it in + # preloaded symbol tables. + # Exclude shared library initialization/finalization symbols. + extract_expsyms_cmds= + # Just being paranoid about ensuring that cc_basename is set. + for cc_temp in $compiler""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`$echo "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"` + + case $host_os in + cygwin* | mingw* | pw32*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test "$GCC" != yes; then + with_gnu_ld=no + fi + ;; + interix*) + # we just hope/assume this is gcc and not c89 (= MSVC++) + with_gnu_ld=yes + ;; + openbsd*) + with_gnu_ld=no + ;; + esac + + ld_shlibs_GCJ=yes + if test "$with_gnu_ld" = yes; then + # If archive_cmds runs LD, not CC, wlarc should be empty + wlarc='${wl}' + + # Set some defaults for GNU ld with shared library support. These + # are reset later if shared libraries are not supported. Putting them + # here allows them to be overridden if necessary. + runpath_var=LD_RUN_PATH + hardcode_libdir_flag_spec_GCJ='${wl}--rpath ${wl}$libdir' + export_dynamic_flag_spec_GCJ='${wl}--export-dynamic' + # ancient GNU ld didn't support --whole-archive et. al. + if $LD --help 2>&1 | grep 'no-whole-archive' > /dev/null; then + whole_archive_flag_spec_GCJ="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + whole_archive_flag_spec_GCJ= + fi + supports_anon_versioning=no + case `$LD -v 2>/dev/null` in + *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11 + *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... + *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... + *\ 2.11.*) ;; # other 2.11 versions + *) supports_anon_versioning=yes ;; + esac + + # See if GNU ld supports shared libraries. + case $host_os in + aix[3-9]*) + # On AIX/PPC, the GNU linker is very broken + if test "$host_cpu" != ia64; then + ld_shlibs_GCJ=no + cat <&2 + +*** Warning: the GNU linker, at least up to release 2.9.1, is reported +*** to be unable to reliably create shared libraries on AIX. +*** Therefore, libtool is disabling shared libraries support. If you +*** really care for shared libraries, you may want to modify your PATH +*** so that a non-GNU linker is found, and then restart. + +EOF + fi + ;; + + amigaos*) + archive_cmds_GCJ='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec_GCJ='-L$libdir' + hardcode_minus_L_GCJ=yes + + # Samuel A. Falvo II reports + # that the semantics of dynamic libraries on AmigaOS, at least up + # to version 4, is to share data among multiple programs linked + # with the same dynamic library. Since this doesn't match the + # behavior of shared libraries on other platforms, we can't use + # them. + ld_shlibs_GCJ=no + ;; + + beos*) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + allow_undefined_flag_GCJ=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + archive_cmds_GCJ='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + ld_shlibs_GCJ=no + fi + ;; + + cygwin* | mingw* | pw32*) + # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, GCJ) is actually meaningless, + # as there is no search path for DLLs. + hardcode_libdir_flag_spec_GCJ='-L$libdir' + allow_undefined_flag_GCJ=unsupported + always_export_symbols_GCJ=no + enable_shared_with_static_runtimes_GCJ=yes + export_symbols_cmds_GCJ='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/'\'' -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols' + + if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then + archive_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + archive_expsym_cmds_GCJ='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + ld_shlibs_GCJ=no + fi + ;; + + interix[3-9]*) + hardcode_direct_GCJ=no + hardcode_shlibpath_var_GCJ=no + hardcode_libdir_flag_spec_GCJ='${wl}-rpath,$libdir' + export_dynamic_flag_spec_GCJ='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + archive_cmds_GCJ='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + archive_expsym_cmds_GCJ='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + + gnu* | linux* | k*bsd*-gnu) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + tmp_addflag= + case $cc_basename,$host_cpu in + pgcc*) # Portland Group C compiler + whole_archive_flag_spec_GCJ='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag' + ;; + pgf77* | pgf90* | pgf95*) # Portland Group f77 and f90 compilers + whole_archive_flag_spec_GCJ='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag -Mnomain' ;; + ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 + tmp_addflag=' -i_dynamic' ;; + efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 + tmp_addflag=' -i_dynamic -nofor_main' ;; + ifc* | ifort*) # Intel Fortran compiler + tmp_addflag=' -nofor_main' ;; + esac + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) # Sun C 5.9 + whole_archive_flag_spec_GCJ='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_sharedflag='-G' ;; + *Sun\ F*) # Sun Fortran 8.3 + tmp_sharedflag='-G' ;; + *) + tmp_sharedflag='-shared' ;; + esac + archive_cmds_GCJ='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + + if test $supports_anon_versioning = yes; then + archive_expsym_cmds_GCJ='$echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + $echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' + fi + else + ld_shlibs_GCJ=no + fi + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + archive_cmds_GCJ='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' + wlarc= + else + archive_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + fi + ;; + + solaris*) + if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then + ld_shlibs_GCJ=no + cat <&2 + +*** Warning: The releases 2.8.* of the GNU linker cannot reliably +*** create shared libraries on Solaris systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.9.1 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +EOF + elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + archive_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs_GCJ=no + fi + ;; + + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) + case `$LD -v 2>&1` in + *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) + ld_shlibs_GCJ=no + cat <<_LT_EOF 1>&2 + +*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not +*** reliably create shared libraries on SCO systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.16.91.0.3 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + ;; + *) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + hardcode_libdir_flag_spec_GCJ='`test -z "$SCOABSPATH" && echo ${wl}-rpath,$libdir`' + archive_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib' + archive_expsym_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname,\${SCOABSPATH:+${install_libdir}/}$soname,-retain-symbols-file,$export_symbols -o $lib' + else + ld_shlibs_GCJ=no + fi + ;; + esac + ;; + + sunos4*) + archive_cmds_GCJ='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' + wlarc= + hardcode_direct_GCJ=yes + hardcode_shlibpath_var_GCJ=no + ;; + + *) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + archive_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs_GCJ=no + fi + ;; + esac + + if test "$ld_shlibs_GCJ" = no; then + runpath_var= + hardcode_libdir_flag_spec_GCJ= + export_dynamic_flag_spec_GCJ= + whole_archive_flag_spec_GCJ= + fi + else + # PORTME fill in a description of your system's linker (not GNU ld) + case $host_os in + aix3*) + allow_undefined_flag_GCJ=unsupported + always_export_symbols_GCJ=yes + archive_expsym_cmds_GCJ='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + hardcode_minus_L_GCJ=yes + if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + hardcode_direct_GCJ=unsupported + fi + ;; + + aix[4-9]*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + if $NM -V 2>&1 | grep 'GNU' > /dev/null; then + export_symbols_cmds_GCJ='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols' + else + export_symbols_cmds_GCJ='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols' + fi + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) + for ld_flag in $LDFLAGS; do + if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then + aix_use_runtimelinking=yes + break + fi + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + archive_cmds_GCJ='' + hardcode_direct_GCJ=yes + hardcode_libdir_separator_GCJ=':' + link_all_deplibs_GCJ=yes + + if test "$GCC" = yes; then + case $host_os in aix4.[012]|aix4.[012].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && \ + strings "$collect2name" | grep resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + hardcode_direct_GCJ=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + hardcode_minus_L_GCJ=yes + hardcode_libdir_flag_spec_GCJ='-L$libdir' + hardcode_libdir_separator_GCJ= + fi + ;; + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to export. + always_export_symbols_GCJ=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + allow_undefined_flag_GCJ='-berok' + # Determine the default libpath from the value encoded in an empty executable. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + +lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\(.*\)$/\1/ + p + } + }' +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then + aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +fi +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + + hardcode_libdir_flag_spec_GCJ='${wl}-blibpath:$libdir:'"$aix_libpath" + archive_expsym_cmds_GCJ="\$CC"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + hardcode_libdir_flag_spec_GCJ='${wl}-R $libdir:/usr/lib:/lib' + allow_undefined_flag_GCJ="-z nodefs" + archive_expsym_cmds_GCJ="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an empty executable. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + +lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\(.*\)$/\1/ + p + } + }' +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then + aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +fi +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + + hardcode_libdir_flag_spec_GCJ='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + no_undefined_flag_GCJ=' ${wl}-bernotok' + allow_undefined_flag_GCJ=' ${wl}-berok' + # Exported symbols can be pulled into shared objects from archives + whole_archive_flag_spec_GCJ='$convenience' + archive_cmds_need_lc_GCJ=yes + # This is similar to how AIX traditionally builds its shared libraries. + archive_expsym_cmds_GCJ="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + amigaos*) + archive_cmds_GCJ='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec_GCJ='-L$libdir' + hardcode_minus_L_GCJ=yes + # see comment about different semantics on the GNU ld section + ld_shlibs_GCJ=no + ;; + + bsdi[45]*) + export_dynamic_flag_spec_GCJ=-rdynamic + ;; + + cygwin* | mingw* | pw32*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + hardcode_libdir_flag_spec_GCJ=' ' + allow_undefined_flag_GCJ=unsupported + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + archive_cmds_GCJ='$CC -o $lib $libobjs $compiler_flags `echo "$deplibs" | $SED -e '\''s/ -lc$//'\''` -link -dll~linknames=' + # The linker will automatically build a .lib file if we build a DLL. + old_archive_From_new_cmds_GCJ='true' + # FIXME: Should let the user specify the lib program. + old_archive_cmds_GCJ='lib -OUT:$oldlib$oldobjs$old_deplibs' + fix_srcfile_path_GCJ='`cygpath -w "$srcfile"`' + enable_shared_with_static_runtimes_GCJ=yes + ;; + + darwin* | rhapsody*) + case $host_os in + rhapsody* | darwin1.[012]) + allow_undefined_flag_GCJ='${wl}-undefined ${wl}suppress' + ;; + *) # Darwin 1.3 on + if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then + allow_undefined_flag_GCJ='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' + else + case ${MACOSX_DEPLOYMENT_TARGET} in + 10.[012]) + allow_undefined_flag_GCJ='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' + ;; + 10.*) + allow_undefined_flag_GCJ='${wl}-undefined ${wl}dynamic_lookup' + ;; + esac + fi + ;; + esac + archive_cmds_need_lc_GCJ=no + hardcode_direct_GCJ=no + hardcode_automatic_GCJ=yes + hardcode_shlibpath_var_GCJ=unsupported + whole_archive_flag_spec_GCJ='' + link_all_deplibs_GCJ=yes + if test "$GCC" = yes ; then + output_verbose_link_cmd='echo' + archive_cmds_GCJ="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" + module_cmds_GCJ="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" + archive_expsym_cmds_GCJ="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" + module_expsym_cmds_GCJ="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" + else + case $cc_basename in + xlc*) + output_verbose_link_cmd='echo' + archive_cmds_GCJ='$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}`echo $rpath/$soname` $xlcverstring' + module_cmds_GCJ='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' + # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds + archive_expsym_cmds_GCJ='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}$rpath/$soname $xlcverstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + module_expsym_cmds_GCJ='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + ;; + *) + ld_shlibs_GCJ=no + ;; + esac + fi + ;; + + dgux*) + archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec_GCJ='-L$libdir' + hardcode_shlibpath_var_GCJ=no + ;; + + freebsd1*) + ld_shlibs_GCJ=no + ;; + + # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor + # support. Future versions do this automatically, but an explicit c++rt0.o + # does not break anything, and helps significantly (at the cost of a little + # extra space). + freebsd2.2*) + archive_cmds_GCJ='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' + hardcode_libdir_flag_spec_GCJ='-R$libdir' + hardcode_direct_GCJ=yes + hardcode_shlibpath_var_GCJ=no + ;; + + # Unfortunately, older versions of FreeBSD 2 do not have this feature. + freebsd2*) + archive_cmds_GCJ='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct_GCJ=yes + hardcode_minus_L_GCJ=yes + hardcode_shlibpath_var_GCJ=no + ;; + + # FreeBSD 3 and greater uses gcc -shared to do shared libraries. + freebsd* | dragonfly*) + archive_cmds_GCJ='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec_GCJ='-R$libdir' + hardcode_direct_GCJ=yes + hardcode_shlibpath_var_GCJ=no + ;; + + hpux9*) + if test "$GCC" = yes; then + archive_cmds_GCJ='$rm $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + archive_cmds_GCJ='$rm $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + fi + hardcode_libdir_flag_spec_GCJ='${wl}+b ${wl}$libdir' + hardcode_libdir_separator_GCJ=: + hardcode_direct_GCJ=yes + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L_GCJ=yes + export_dynamic_flag_spec_GCJ='${wl}-E' + ;; + + hpux10*) + if test "$GCC" = yes -a "$with_gnu_ld" = no; then + archive_cmds_GCJ='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds_GCJ='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' + fi + if test "$with_gnu_ld" = no; then + hardcode_libdir_flag_spec_GCJ='${wl}+b ${wl}$libdir' + hardcode_libdir_separator_GCJ=: + + hardcode_direct_GCJ=yes + export_dynamic_flag_spec_GCJ='${wl}-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L_GCJ=yes + fi + ;; + + hpux11*) + if test "$GCC" = yes -a "$with_gnu_ld" = no; then + case $host_cpu in + hppa*64*) + archive_cmds_GCJ='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + archive_cmds_GCJ='$CC -shared ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + archive_cmds_GCJ='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + else + case $host_cpu in + hppa*64*) + archive_cmds_GCJ='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + archive_cmds_GCJ='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + archive_cmds_GCJ='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + fi + if test "$with_gnu_ld" = no; then + hardcode_libdir_flag_spec_GCJ='${wl}+b ${wl}$libdir' + hardcode_libdir_separator_GCJ=: + + case $host_cpu in + hppa*64*|ia64*) + hardcode_libdir_flag_spec_ld_GCJ='+b $libdir' + hardcode_direct_GCJ=no + hardcode_shlibpath_var_GCJ=no + ;; + *) + hardcode_direct_GCJ=yes + export_dynamic_flag_spec_GCJ='${wl}-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L_GCJ=yes + ;; + esac + fi + ;; + + irix5* | irix6* | nonstopux*) + if test "$GCC" = yes; then + archive_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + archive_cmds_GCJ='$LD -shared $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + hardcode_libdir_flag_spec_ld_GCJ='-rpath $libdir' + fi + hardcode_libdir_flag_spec_GCJ='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator_GCJ=: + link_all_deplibs_GCJ=yes + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + archive_cmds_GCJ='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out + else + archive_cmds_GCJ='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF + fi + hardcode_libdir_flag_spec_GCJ='-R$libdir' + hardcode_direct_GCJ=yes + hardcode_shlibpath_var_GCJ=no + ;; + + newsos6) + archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct_GCJ=yes + hardcode_libdir_flag_spec_GCJ='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator_GCJ=: + hardcode_shlibpath_var_GCJ=no + ;; + + openbsd*) + if test -f /usr/libexec/ld.so; then + hardcode_direct_GCJ=yes + hardcode_shlibpath_var_GCJ=no + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + archive_cmds_GCJ='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_GCJ='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' + hardcode_libdir_flag_spec_GCJ='${wl}-rpath,$libdir' + export_dynamic_flag_spec_GCJ='${wl}-E' + else + case $host_os in + openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) + archive_cmds_GCJ='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec_GCJ='-R$libdir' + ;; + *) + archive_cmds_GCJ='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec_GCJ='${wl}-rpath,$libdir' + ;; + esac + fi + else + ld_shlibs_GCJ=no + fi + ;; + + os2*) + hardcode_libdir_flag_spec_GCJ='-L$libdir' + hardcode_minus_L_GCJ=yes + allow_undefined_flag_GCJ=unsupported + archive_cmds_GCJ='$echo "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$echo DATA >> $output_objdir/$libname.def~$echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~$echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' + old_archive_From_new_cmds_GCJ='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' + ;; + + osf3*) + if test "$GCC" = yes; then + allow_undefined_flag_GCJ=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds_GCJ='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + allow_undefined_flag_GCJ=' -expect_unresolved \*' + archive_cmds_GCJ='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + fi + hardcode_libdir_flag_spec_GCJ='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator_GCJ=: + ;; + + osf4* | osf5*) # as osf3* with the addition of -msym flag + if test "$GCC" = yes; then + allow_undefined_flag_GCJ=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds_GCJ='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + hardcode_libdir_flag_spec_GCJ='${wl}-rpath ${wl}$libdir' + else + allow_undefined_flag_GCJ=' -expect_unresolved \*' + archive_cmds_GCJ='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + archive_expsym_cmds_GCJ='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; echo "-hidden">> $lib.exp~ + $LD -shared${allow_undefined_flag} -input $lib.exp $linker_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib~$rm $lib.exp' + + # Both c and cxx compiler support -rpath directly + hardcode_libdir_flag_spec_GCJ='-rpath $libdir' + fi + hardcode_libdir_separator_GCJ=: + ;; + + solaris*) + no_undefined_flag_GCJ=' -z text' + if test "$GCC" = yes; then + wlarc='${wl}' + archive_cmds_GCJ='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_GCJ='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -shared ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$rm $lib.exp' + else + wlarc='' + archive_cmds_GCJ='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' + archive_expsym_cmds_GCJ='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp' + fi + hardcode_libdir_flag_spec_GCJ='-R$libdir' + hardcode_shlibpath_var_GCJ=no + case $host_os in + solaris2.[0-5] | solaris2.[0-5].*) ;; + *) + # The compiler driver will combine and reorder linker options, + # but understands `-z linker_flag'. GCC discards it without `$wl', + # but is careful enough not to reorder. + # Supported since Solaris 2.6 (maybe 2.5.1?) + if test "$GCC" = yes; then + whole_archive_flag_spec_GCJ='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' + else + whole_archive_flag_spec_GCJ='-z allextract$convenience -z defaultextract' + fi + ;; + esac + link_all_deplibs_GCJ=yes + ;; + + sunos4*) + if test "x$host_vendor" = xsequent; then + # Use $CC to link under sequent, because it throws in some extra .o + # files that make .init and .fini sections work. + archive_cmds_GCJ='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds_GCJ='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' + fi + hardcode_libdir_flag_spec_GCJ='-L$libdir' + hardcode_direct_GCJ=yes + hardcode_minus_L_GCJ=yes + hardcode_shlibpath_var_GCJ=no + ;; + + sysv4) + case $host_vendor in + sni) + archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct_GCJ=yes # is this really true??? + ;; + siemens) + ## LD is ld it makes a PLAMLIB + ## CC just makes a GrossModule. + archive_cmds_GCJ='$LD -G -o $lib $libobjs $deplibs $linker_flags' + reload_cmds_GCJ='$CC -r -o $output$reload_objs' + hardcode_direct_GCJ=no + ;; + motorola) + archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct_GCJ=no #Motorola manual says yes, but my tests say they lie + ;; + esac + runpath_var='LD_RUN_PATH' + hardcode_shlibpath_var_GCJ=no + ;; + + sysv4.3*) + archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var_GCJ=no + export_dynamic_flag_spec_GCJ='-Bexport' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var_GCJ=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + ld_shlibs_GCJ=yes + fi + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) + no_undefined_flag_GCJ='${wl}-z,text' + archive_cmds_need_lc_GCJ=no + hardcode_shlibpath_var_GCJ=no + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + archive_cmds_GCJ='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_GCJ='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds_GCJ='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_GCJ='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + no_undefined_flag_GCJ='${wl}-z,text' + allow_undefined_flag_GCJ='${wl}-z,nodefs' + archive_cmds_need_lc_GCJ=no + hardcode_shlibpath_var_GCJ=no + hardcode_libdir_flag_spec_GCJ='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`' + hardcode_libdir_separator_GCJ=':' + link_all_deplibs_GCJ=yes + export_dynamic_flag_spec_GCJ='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + archive_cmds_GCJ='$CC -shared ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_GCJ='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds_GCJ='$CC -G ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_GCJ='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + uts4*) + archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec_GCJ='-L$libdir' + hardcode_shlibpath_var_GCJ=no + ;; + + *) + ld_shlibs_GCJ=no + ;; + esac + fi + +{ echo "$as_me:$LINENO: result: $ld_shlibs_GCJ" >&5 +echo "${ECHO_T}$ld_shlibs_GCJ" >&6; } +test "$ld_shlibs_GCJ" = no && can_build_shared=no + +# +# Do we need to explicitly link libc? +# +case "x$archive_cmds_need_lc_GCJ" in +x|xyes) + # Assume -lc should be added + archive_cmds_need_lc_GCJ=yes + + if test "$enable_shared" = yes && test "$GCC" = yes; then + case $archive_cmds_GCJ in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + { echo "$as_me:$LINENO: checking whether -lc should be explicitly linked in" >&5 +echo $ECHO_N "checking whether -lc should be explicitly linked in... $ECHO_C" >&6; } + $rm conftest* + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$lt_prog_compiler_wl_GCJ + pic_flag=$lt_prog_compiler_pic_GCJ + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$allow_undefined_flag_GCJ + allow_undefined_flag_GCJ= + if { (eval echo "$as_me:$LINENO: \"$archive_cmds_GCJ 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1\"") >&5 + (eval $archive_cmds_GCJ 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + then + archive_cmds_need_lc_GCJ=no + else + archive_cmds_need_lc_GCJ=yes + fi + allow_undefined_flag_GCJ=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $rm conftest* + { echo "$as_me:$LINENO: result: $archive_cmds_need_lc_GCJ" >&5 +echo "${ECHO_T}$archive_cmds_need_lc_GCJ" >&6; } + ;; + esac + fi + ;; +esac + +{ echo "$as_me:$LINENO: checking dynamic linker characteristics" >&5 +echo $ECHO_N "checking dynamic linker characteristics... $ECHO_C" >&6; } +library_names_spec= +libname_spec='lib$name' +soname_spec= +shrext_cmds=".so" +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" + +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + +case $host_os in +aix3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='${libname}${release}${shared_ext}$major' + ;; + +aix[4-9]*) + version_type=linux + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test "$host_cpu" = ia64; then + # AIX 5 supports IA64 + library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line `#! .'. This would cause the generated library to + # depend on `.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[01] | aix4.[01].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # AIX (on Power*) has no versioning support, so currently we can not hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + if test "$aix_use_runtimelinking" = yes; then + # If using run time linking (on AIX 4.2 or later) use lib.so + # instead of lib.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + else + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='${libname}${release}.a $libname.a' + soname_spec='${libname}${release}${shared_ext}$major' + fi + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' + ;; + +beos*) + library_names_spec='${libname}${shared_ext}' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi[45]*) + version_type=linux + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32*) + version_type=windows + shrext_cmds=".dll" + need_version=no + need_lib_prefix=no + + case $GCC,$host_os in + yes,cygwin* | yes,mingw* | yes,pw32*) + library_names_spec='$libname.dll.a' + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i;echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $rm \$dlpath' + shlibpath_overrides_runpath=yes + + case $host_os in + cygwin*) + # Cygwin DLLs use 'cyg' prefix rather than 'lib' + soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib" + ;; + mingw*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if echo "$sys_lib_search_path_spec" | grep ';[c-zC-Z]:/' >/dev/null; then + # It is most probably a Windows format PATH printed by + # mingw gcc, but we are running on Cygwin. Gcc prints its search + # path with ; separators, and with drive letters. We can handle the + # drive letters (cygwin fileutils understands them), so leave them, + # especially as we might pass files found there to a mingw objdump, + # which wouldn't understand a cygwinified path. Ahh. + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + ;; + pw32*) + # pw32 DLLs use 'pw' prefix rather than 'lib' + library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + ;; + esac + ;; + + *) + library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' + ;; + esac + dynamic_linker='Win32 ld.exe' + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${versuffix}$shared_ext ${libname}${release}${major}$shared_ext ${libname}$shared_ext' + soname_spec='${libname}${release}${major}$shared_ext' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' + + sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd1*) + dynamic_linker=no + ;; + +freebsd* | dragonfly*) + # DragonFly does not have aout. When/if they implement a new + # versioning mechanism, adjust this. + if test -x /usr/bin/objformat; then + objformat=`/usr/bin/objformat` + else + case $host_os in + freebsd[123]*) objformat=aout ;; + *) objformat=elf ;; + esac + fi + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[01]* | freebsdelf3.[01]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ + freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + *) # from 4.6 on, and DragonFly + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + esac + ;; + +gnu*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + case $host_cpu in + ia64*) + shrext_cmds='.so' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + if test "X$HPUX_IA64_MODE" = X32; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + fi + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + hppa*64*) + shrext_cmds='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) + shrext_cmds='.sl' + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + ;; + esac + # HP-UX runs *really* slowly unless shared libraries are mode 555. + postinstall_cmds='chmod 555 $lib' + ;; + +interix[3-9]*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) + if test "$lt_cv_prog_gnu_ld" = yes; then + version_type=linux + else + version_type=irix + fi ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") + libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") + libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") + libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" + sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" + hardcode_into_libs=yes + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +# This must be Linux ELF. +linux* | k*bsd*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # Append ld.so.conf contents to the search path + if test -f /etc/ld.so.conf; then + lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '` + sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" + fi + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +nto-qnx*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +openbsd*) + version_type=sunos + sys_lib_dlsearch_path_spec="/usr/lib" + need_lib_prefix=no + # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. + case $host_os in + openbsd3.3 | openbsd3.3.*) need_version=yes ;; + *) need_version=no ;; + esac + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + case $host_os in + openbsd2.[89] | openbsd2.[89].*) + shlibpath_overrides_runpath=no + ;; + *) + shlibpath_overrides_runpath=yes + ;; + esac + else + shlibpath_overrides_runpath=yes + fi + ;; + +os2*) + libname_spec='$name' + shrext_cmds=".dll" + need_lib_prefix=no + library_names_spec='$libname${shared_ext} $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + ;; + +rdos*) + dynamic_linker=no + ;; + +solaris*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + export_dynamic_flag_spec='${wl}-Blargedynsym' + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec ;then + version_type=linux + library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' + soname_spec='$libname${shared_ext}.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + version_type=freebsd-elf + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + if test "$with_gnu_ld" = yes; then + sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' + shlibpath_overrides_runpath=no + else + sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' + shlibpath_overrides_runpath=yes + case $host_os in + sco3.2v5*) + sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" + ;; + esac + fi + sys_lib_dlsearch_path_spec='/usr/lib' + ;; + +uts4*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +{ echo "$as_me:$LINENO: result: $dynamic_linker" >&5 +echo "${ECHO_T}$dynamic_linker" >&6; } +test "$dynamic_linker" = no && can_build_shared=no + +if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_cv_sys_lib_search_path_spec="$sys_lib_search_path_spec" +fi + +sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" +if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_cv_sys_lib_dlsearch_path_spec="$sys_lib_dlsearch_path_spec" +fi + +sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test "$GCC" = yes; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +{ echo "$as_me:$LINENO: checking how to hardcode library paths into programs" >&5 +echo $ECHO_N "checking how to hardcode library paths into programs... $ECHO_C" >&6; } +hardcode_action_GCJ= +if test -n "$hardcode_libdir_flag_spec_GCJ" || \ + test -n "$runpath_var_GCJ" || \ + test "X$hardcode_automatic_GCJ" = "Xyes" ; then + + # We can hardcode non-existant directories. + if test "$hardcode_direct_GCJ" != no && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test "$_LT_AC_TAGVAR(hardcode_shlibpath_var, GCJ)" != no && + test "$hardcode_minus_L_GCJ" != no; then + # Linking always hardcodes the temporary library directory. + hardcode_action_GCJ=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + hardcode_action_GCJ=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + hardcode_action_GCJ=unsupported +fi +{ echo "$as_me:$LINENO: result: $hardcode_action_GCJ" >&5 +echo "${ECHO_T}$hardcode_action_GCJ" >&6; } + +if test "$hardcode_action_GCJ" = relink; then + # Fast installation is not supported + enable_fast_install=no +elif test "$shlibpath_overrides_runpath" = yes || + test "$enable_shared" = no; then + # Fast installation is not necessary + enable_fast_install=needless +fi + + +# The else clause should only fire when bootstrapping the +# libtool distribution, otherwise you forgot to ship ltmain.sh +# with your package, and you will get complaints that there are +# no rules to generate ltmain.sh. +if test -f "$ltmain"; then + # See if we are running on zsh, and set the options which allow our commands through + # without removal of \ escapes. + if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST + fi + # Now quote all the things that may contain metacharacters while being + # careful not to overquote the AC_SUBSTed values. We take copies of the + # variables and quote the copies for generation of the libtool script. + for var in echo old_CC old_CFLAGS AR AR_FLAGS EGREP RANLIB LN_S LTCC LTCFLAGS NM \ + SED SHELL STRIP \ + libname_spec library_names_spec soname_spec extract_expsyms_cmds \ + old_striplib striplib file_magic_cmd finish_cmds finish_eval \ + deplibs_check_method reload_flag reload_cmds need_locks \ + lt_cv_sys_global_symbol_pipe lt_cv_sys_global_symbol_to_cdecl \ + lt_cv_sys_global_symbol_to_c_name_address \ + sys_lib_search_path_spec sys_lib_dlsearch_path_spec \ + old_postinstall_cmds old_postuninstall_cmds \ + compiler_GCJ \ + CC_GCJ \ + LD_GCJ \ + lt_prog_compiler_wl_GCJ \ + lt_prog_compiler_pic_GCJ \ + lt_prog_compiler_static_GCJ \ + lt_prog_compiler_no_builtin_flag_GCJ \ + export_dynamic_flag_spec_GCJ \ + thread_safe_flag_spec_GCJ \ + whole_archive_flag_spec_GCJ \ + enable_shared_with_static_runtimes_GCJ \ + old_archive_cmds_GCJ \ + old_archive_from_new_cmds_GCJ \ + predep_objects_GCJ \ + postdep_objects_GCJ \ + predeps_GCJ \ + postdeps_GCJ \ + compiler_lib_search_path_GCJ \ + compiler_lib_search_dirs_GCJ \ + archive_cmds_GCJ \ + archive_expsym_cmds_GCJ \ + postinstall_cmds_GCJ \ + postuninstall_cmds_GCJ \ + old_archive_from_expsyms_cmds_GCJ \ + allow_undefined_flag_GCJ \ + no_undefined_flag_GCJ \ + export_symbols_cmds_GCJ \ + hardcode_libdir_flag_spec_GCJ \ + hardcode_libdir_flag_spec_ld_GCJ \ + hardcode_libdir_separator_GCJ \ + hardcode_automatic_GCJ \ + module_cmds_GCJ \ + module_expsym_cmds_GCJ \ + lt_cv_prog_compiler_c_o_GCJ \ + fix_srcfile_path_GCJ \ + exclude_expsyms_GCJ \ + include_expsyms_GCJ; do + + case $var in + old_archive_cmds_GCJ | \ + old_archive_from_new_cmds_GCJ | \ + archive_cmds_GCJ | \ + archive_expsym_cmds_GCJ | \ + module_cmds_GCJ | \ + module_expsym_cmds_GCJ | \ + old_archive_from_expsyms_cmds_GCJ | \ + export_symbols_cmds_GCJ | \ + extract_expsyms_cmds | reload_cmds | finish_cmds | \ + postinstall_cmds | postuninstall_cmds | \ + old_postinstall_cmds | old_postuninstall_cmds | \ + sys_lib_search_path_spec | sys_lib_dlsearch_path_spec) + # Double-quote double-evaled strings. + eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\"" + ;; + *) + eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\"" + ;; + esac + done + + case $lt_echo in + *'\$0 --fallback-echo"') + lt_echo=`$echo "X$lt_echo" | $Xsed -e 's/\\\\\\\$0 --fallback-echo"$/$0 --fallback-echo"/'` + ;; + esac + +cfgfile="$ofile" + + cat <<__EOF__ >> "$cfgfile" +# ### BEGIN LIBTOOL TAG CONFIG: $tagname + +# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: + +# Shell to use when invoking shell scripts. +SHELL=$lt_SHELL + +# Whether or not to build shared libraries. +build_libtool_libs=$enable_shared + +# Whether or not to build static libraries. +build_old_libs=$enable_static + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=$archive_cmds_need_lc_GCJ + +# Whether or not to disallow shared libs when runtime libs are static +allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_GCJ + +# Whether or not to optimize for fast installation. +fast_install=$enable_fast_install + +# The host system. +host_alias=$host_alias +host=$host +host_os=$host_os + +# The build system. +build_alias=$build_alias +build=$build +build_os=$build_os + +# An echo program that does not interpret backslashes. +echo=$lt_echo + +# The archiver. +AR=$lt_AR +AR_FLAGS=$lt_AR_FLAGS + +# A C compiler. +LTCC=$lt_LTCC + +# LTCC compiler flags. +LTCFLAGS=$lt_LTCFLAGS + +# A language-specific compiler. +CC=$lt_compiler_GCJ + +# Is the compiler the GNU C compiler? +with_gcc=$GCC_GCJ + +# An ERE matcher. +EGREP=$lt_EGREP + +# The linker used to build libraries. +LD=$lt_LD_GCJ + +# Whether we need hard or soft links. +LN_S=$lt_LN_S + +# A BSD-compatible nm program. +NM=$lt_NM + +# A symbol stripping program +STRIP=$lt_STRIP + +# Used to examine libraries when file_magic_cmd begins "file" +MAGIC_CMD=$MAGIC_CMD + +# Used on cygwin: DLL creation program. +DLLTOOL="$DLLTOOL" + +# Used on cygwin: object dumper. +OBJDUMP="$OBJDUMP" + +# Used on cygwin: assembler. +AS="$AS" + +# The name of the directory that contains temporary libtool files. +objdir=$objdir + +# How to create reloadable object files. +reload_flag=$lt_reload_flag +reload_cmds=$lt_reload_cmds + +# How to pass a linker flag through the compiler. +wl=$lt_lt_prog_compiler_wl_GCJ + +# Object file suffix (normally "o"). +objext="$ac_objext" + +# Old archive suffix (normally "a"). +libext="$libext" + +# Shared library suffix (normally ".so"). +shrext_cmds='$shrext_cmds' + +# Executable file suffix (normally ""). +exeext="$exeext" + +# Additional compiler flags for building library objects. +pic_flag=$lt_lt_prog_compiler_pic_GCJ +pic_mode=$pic_mode + +# What is the maximum length of a command? +max_cmd_len=$lt_cv_sys_max_cmd_len + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$lt_lt_cv_prog_compiler_c_o_GCJ + +# Must we lock files when doing compilation? +need_locks=$lt_need_locks + +# Do we need the lib prefix for modules? +need_lib_prefix=$need_lib_prefix + +# Do we need a version for libraries? +need_version=$need_version + +# Whether dlopen is supported. +dlopen_support=$enable_dlopen + +# Whether dlopen of programs is supported. +dlopen_self=$enable_dlopen_self + +# Whether dlopen of statically linked programs is supported. +dlopen_self_static=$enable_dlopen_self_static + +# Compiler flag to prevent dynamic linking. +link_static_flag=$lt_lt_prog_compiler_static_GCJ + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_GCJ + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_GCJ + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec=$lt_whole_archive_flag_spec_GCJ + +# Compiler flag to generate thread-safe objects. +thread_safe_flag_spec=$lt_thread_safe_flag_spec_GCJ + +# Library versioning type. +version_type=$version_type + +# Format of library name prefix. +libname_spec=$lt_libname_spec + +# List of archive names. First name is the real one, the rest are links. +# The last name is the one that the linker finds with -lNAME. +library_names_spec=$lt_library_names_spec + +# The coded name of the library, if different from the real name. +soname_spec=$lt_soname_spec + +# Commands used to build and install an old-style archive. +RANLIB=$lt_RANLIB +old_archive_cmds=$lt_old_archive_cmds_GCJ +old_postinstall_cmds=$lt_old_postinstall_cmds +old_postuninstall_cmds=$lt_old_postuninstall_cmds + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_GCJ + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_GCJ + +# Commands used to build and install a shared archive. +archive_cmds=$lt_archive_cmds_GCJ +archive_expsym_cmds=$lt_archive_expsym_cmds_GCJ +postinstall_cmds=$lt_postinstall_cmds +postuninstall_cmds=$lt_postuninstall_cmds + +# Commands used to build a loadable module (assumed same as above if empty) +module_cmds=$lt_module_cmds_GCJ +module_expsym_cmds=$lt_module_expsym_cmds_GCJ + +# Commands to strip libraries. +old_striplib=$lt_old_striplib +striplib=$lt_striplib + +# Dependencies to place before the objects being linked to create a +# shared library. +predep_objects=$lt_predep_objects_GCJ + +# Dependencies to place after the objects being linked to create a +# shared library. +postdep_objects=$lt_postdep_objects_GCJ + +# Dependencies to place before the objects being linked to create a +# shared library. +predeps=$lt_predeps_GCJ + +# Dependencies to place after the objects being linked to create a +# shared library. +postdeps=$lt_postdeps_GCJ + +# The directories searched by this compiler when creating a shared +# library +compiler_lib_search_dirs=$lt_compiler_lib_search_dirs_GCJ + +# The library search path used internally by the compiler when linking +# a shared library. +compiler_lib_search_path=$lt_compiler_lib_search_path_GCJ + +# Method to check whether dependent libraries are shared objects. +deplibs_check_method=$lt_deplibs_check_method + +# Command to use when deplibs_check_method == file_magic. +file_magic_cmd=$lt_file_magic_cmd + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$lt_allow_undefined_flag_GCJ + +# Flag that forces no undefined symbols. +no_undefined_flag=$lt_no_undefined_flag_GCJ + +# Commands used to finish a libtool library installation in a directory. +finish_cmds=$lt_finish_cmds + +# Same as above, but a single script fragment to be evaled but not shown. +finish_eval=$lt_finish_eval + +# Take the output of nm and produce a listing of raw symbols and C names. +global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe + +# Transform the output of nm in a proper C declaration +global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl + +# Transform the output of nm in a C name address pair +global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address + +# This is the shared library runtime path variable. +runpath_var=$runpath_var + +# This is the shared library path variable. +shlibpath_var=$shlibpath_var + +# Is shlibpath searched before the hard-coded library search path? +shlibpath_overrides_runpath=$shlibpath_overrides_runpath + +# How to hardcode a shared library path into an executable. +hardcode_action=$hardcode_action_GCJ + +# Whether we should hardcode library paths into libraries. +hardcode_into_libs=$hardcode_into_libs + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist. +hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_GCJ + +# If ld is used when linking, flag to hardcode \$libdir into +# a binary during linking. This must work even if \$libdir does +# not exist. +hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld_GCJ + +# Whether we need a single -rpath flag with a separated argument. +hardcode_libdir_separator=$lt_hardcode_libdir_separator_GCJ + +# Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the +# resulting binary. +hardcode_direct=$hardcode_direct_GCJ + +# Set to yes if using the -LDIR flag during linking hardcodes DIR into the +# resulting binary. +hardcode_minus_L=$hardcode_minus_L_GCJ + +# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into +# the resulting binary. +hardcode_shlibpath_var=$hardcode_shlibpath_var_GCJ + +# Set to yes if building a shared library automatically hardcodes DIR into the library +# and all subsequent libraries and executables linked against it. +hardcode_automatic=$hardcode_automatic_GCJ + +# Variables whose values should be saved in libtool wrapper scripts and +# restored at relink time. +variables_saved_for_relink="$variables_saved_for_relink" + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=$link_all_deplibs_GCJ + +# Compile-time system search path for libraries +sys_lib_search_path_spec=$lt_sys_lib_search_path_spec + +# Run-time system search path for libraries +sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec + +# Fix the shell variable \$srcfile for the compiler. +fix_srcfile_path=$lt_fix_srcfile_path + +# Set to yes if exported symbols are required. +always_export_symbols=$always_export_symbols_GCJ + +# The commands to list exported symbols. +export_symbols_cmds=$lt_export_symbols_cmds_GCJ + +# The commands to extract the exported symbol list from a shared archive. +extract_expsyms_cmds=$lt_extract_expsyms_cmds + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms=$lt_exclude_expsyms_GCJ + +# Symbols that must always be exported. +include_expsyms=$lt_include_expsyms_GCJ + +# ### END LIBTOOL TAG CONFIG: $tagname + +__EOF__ + + +else + # If there is no Makefile yet, we rely on a make rule to execute + # `config.status --recheck' to rerun these tests and create the + # libtool script then. + ltmain_in=`echo $ltmain | sed -e 's/\.sh$/.in/'` + if test -f "$ltmain_in"; then + test -f Makefile && make "$ltmain" + 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 + +CC="$lt_save_CC" + + else + tagname="" + fi + ;; + + RC) + + +# Source file extension for RC test sources. +ac_ext=rc + +# Object file extension for compiled RC test sources. +objext=o +objext_RC=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }' + +# Code to be used in simple link tests +lt_simple_link_test_code="$lt_simple_compile_test_code" + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC + + +# save warnings/boilerplate of simple test code +ac_outfile=conftest.$ac_objext +echo "$lt_simple_compile_test_code" >conftest.$ac_ext +eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_compiler_boilerplate=`cat conftest.err` +$rm conftest* + +ac_outfile=conftest.$ac_objext +echo "$lt_simple_link_test_code" >conftest.$ac_ext +eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_linker_boilerplate=`cat conftest.err` +$rm -r conftest* + + +# Allow CC to be a program name with arguments. +lt_save_CC="$CC" +CC=${RC-"windres"} +compiler=$CC +compiler_RC=$CC +for cc_temp in $compiler""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`$echo "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"` + +lt_cv_prog_compiler_c_o_RC=yes + +# The else clause should only fire when bootstrapping the +# libtool distribution, otherwise you forgot to ship ltmain.sh +# with your package, and you will get complaints that there are +# no rules to generate ltmain.sh. +if test -f "$ltmain"; then + # See if we are running on zsh, and set the options which allow our commands through + # without removal of \ escapes. + if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST + fi + # Now quote all the things that may contain metacharacters while being + # careful not to overquote the AC_SUBSTed values. We take copies of the + # variables and quote the copies for generation of the libtool script. + for var in echo old_CC old_CFLAGS AR AR_FLAGS EGREP RANLIB LN_S LTCC LTCFLAGS NM \ + SED SHELL STRIP \ + libname_spec library_names_spec soname_spec extract_expsyms_cmds \ + old_striplib striplib file_magic_cmd finish_cmds finish_eval \ + deplibs_check_method reload_flag reload_cmds need_locks \ + lt_cv_sys_global_symbol_pipe lt_cv_sys_global_symbol_to_cdecl \ + lt_cv_sys_global_symbol_to_c_name_address \ + sys_lib_search_path_spec sys_lib_dlsearch_path_spec \ + old_postinstall_cmds old_postuninstall_cmds \ + compiler_RC \ + CC_RC \ + LD_RC \ + lt_prog_compiler_wl_RC \ + lt_prog_compiler_pic_RC \ + lt_prog_compiler_static_RC \ + lt_prog_compiler_no_builtin_flag_RC \ + export_dynamic_flag_spec_RC \ + thread_safe_flag_spec_RC \ + whole_archive_flag_spec_RC \ + enable_shared_with_static_runtimes_RC \ + old_archive_cmds_RC \ + old_archive_from_new_cmds_RC \ + predep_objects_RC \ + postdep_objects_RC \ + predeps_RC \ + postdeps_RC \ + compiler_lib_search_path_RC \ + compiler_lib_search_dirs_RC \ + archive_cmds_RC \ + archive_expsym_cmds_RC \ + postinstall_cmds_RC \ + postuninstall_cmds_RC \ + old_archive_from_expsyms_cmds_RC \ + allow_undefined_flag_RC \ + no_undefined_flag_RC \ + export_symbols_cmds_RC \ + hardcode_libdir_flag_spec_RC \ + hardcode_libdir_flag_spec_ld_RC \ + hardcode_libdir_separator_RC \ + hardcode_automatic_RC \ + module_cmds_RC \ + module_expsym_cmds_RC \ + lt_cv_prog_compiler_c_o_RC \ + fix_srcfile_path_RC \ + exclude_expsyms_RC \ + include_expsyms_RC; do + + case $var in + old_archive_cmds_RC | \ + old_archive_from_new_cmds_RC | \ + archive_cmds_RC | \ + archive_expsym_cmds_RC | \ + module_cmds_RC | \ + module_expsym_cmds_RC | \ + old_archive_from_expsyms_cmds_RC | \ + export_symbols_cmds_RC | \ + extract_expsyms_cmds | reload_cmds | finish_cmds | \ + postinstall_cmds | postuninstall_cmds | \ + old_postinstall_cmds | old_postuninstall_cmds | \ + sys_lib_search_path_spec | sys_lib_dlsearch_path_spec) + # Double-quote double-evaled strings. + eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\"" + ;; + *) + eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\"" + ;; + esac + done + + case $lt_echo in + *'\$0 --fallback-echo"') + lt_echo=`$echo "X$lt_echo" | $Xsed -e 's/\\\\\\\$0 --fallback-echo"$/$0 --fallback-echo"/'` + ;; + esac + +cfgfile="$ofile" + + cat <<__EOF__ >> "$cfgfile" +# ### BEGIN LIBTOOL TAG CONFIG: $tagname + +# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: + +# Shell to use when invoking shell scripts. +SHELL=$lt_SHELL + +# Whether or not to build shared libraries. +build_libtool_libs=$enable_shared + +# Whether or not to build static libraries. +build_old_libs=$enable_static + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=$archive_cmds_need_lc_RC + +# Whether or not to disallow shared libs when runtime libs are static +allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_RC + +# Whether or not to optimize for fast installation. +fast_install=$enable_fast_install + +# The host system. +host_alias=$host_alias +host=$host +host_os=$host_os + +# The build system. +build_alias=$build_alias +build=$build +build_os=$build_os + +# An echo program that does not interpret backslashes. +echo=$lt_echo + +# The archiver. +AR=$lt_AR +AR_FLAGS=$lt_AR_FLAGS + +# A C compiler. +LTCC=$lt_LTCC + +# LTCC compiler flags. +LTCFLAGS=$lt_LTCFLAGS + +# A language-specific compiler. +CC=$lt_compiler_RC + +# Is the compiler the GNU C compiler? +with_gcc=$GCC_RC + +# An ERE matcher. +EGREP=$lt_EGREP + +# The linker used to build libraries. +LD=$lt_LD_RC + +# Whether we need hard or soft links. +LN_S=$lt_LN_S + +# A BSD-compatible nm program. +NM=$lt_NM + +# A symbol stripping program +STRIP=$lt_STRIP + +# Used to examine libraries when file_magic_cmd begins "file" +MAGIC_CMD=$MAGIC_CMD + +# Used on cygwin: DLL creation program. +DLLTOOL="$DLLTOOL" + +# Used on cygwin: object dumper. +OBJDUMP="$OBJDUMP" + +# Used on cygwin: assembler. +AS="$AS" + +# The name of the directory that contains temporary libtool files. +objdir=$objdir + +# How to create reloadable object files. +reload_flag=$lt_reload_flag +reload_cmds=$lt_reload_cmds + +# How to pass a linker flag through the compiler. +wl=$lt_lt_prog_compiler_wl_RC + +# Object file suffix (normally "o"). +objext="$ac_objext" + +# Old archive suffix (normally "a"). +libext="$libext" + +# Shared library suffix (normally ".so"). +shrext_cmds='$shrext_cmds' + +# Executable file suffix (normally ""). +exeext="$exeext" + +# Additional compiler flags for building library objects. +pic_flag=$lt_lt_prog_compiler_pic_RC +pic_mode=$pic_mode + +# What is the maximum length of a command? +max_cmd_len=$lt_cv_sys_max_cmd_len + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$lt_lt_cv_prog_compiler_c_o_RC + +# Must we lock files when doing compilation? +need_locks=$lt_need_locks + +# Do we need the lib prefix for modules? +need_lib_prefix=$need_lib_prefix + +# Do we need a version for libraries? +need_version=$need_version + +# Whether dlopen is supported. +dlopen_support=$enable_dlopen + +# Whether dlopen of programs is supported. +dlopen_self=$enable_dlopen_self + +# Whether dlopen of statically linked programs is supported. +dlopen_self_static=$enable_dlopen_self_static + +# Compiler flag to prevent dynamic linking. +link_static_flag=$lt_lt_prog_compiler_static_RC + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_RC + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_RC + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec=$lt_whole_archive_flag_spec_RC + +# Compiler flag to generate thread-safe objects. +thread_safe_flag_spec=$lt_thread_safe_flag_spec_RC + +# Library versioning type. +version_type=$version_type + +# Format of library name prefix. +libname_spec=$lt_libname_spec + +# List of archive names. First name is the real one, the rest are links. +# The last name is the one that the linker finds with -lNAME. +library_names_spec=$lt_library_names_spec + +# The coded name of the library, if different from the real name. +soname_spec=$lt_soname_spec + +# Commands used to build and install an old-style archive. +RANLIB=$lt_RANLIB +old_archive_cmds=$lt_old_archive_cmds_RC +old_postinstall_cmds=$lt_old_postinstall_cmds +old_postuninstall_cmds=$lt_old_postuninstall_cmds + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_RC + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_RC + +# Commands used to build and install a shared archive. +archive_cmds=$lt_archive_cmds_RC +archive_expsym_cmds=$lt_archive_expsym_cmds_RC +postinstall_cmds=$lt_postinstall_cmds +postuninstall_cmds=$lt_postuninstall_cmds + +# Commands used to build a loadable module (assumed same as above if empty) +module_cmds=$lt_module_cmds_RC +module_expsym_cmds=$lt_module_expsym_cmds_RC + +# Commands to strip libraries. +old_striplib=$lt_old_striplib +striplib=$lt_striplib + +# Dependencies to place before the objects being linked to create a +# shared library. +predep_objects=$lt_predep_objects_RC + +# Dependencies to place after the objects being linked to create a +# shared library. +postdep_objects=$lt_postdep_objects_RC + +# Dependencies to place before the objects being linked to create a +# shared library. +predeps=$lt_predeps_RC + +# Dependencies to place after the objects being linked to create a +# shared library. +postdeps=$lt_postdeps_RC + +# The directories searched by this compiler when creating a shared +# library +compiler_lib_search_dirs=$lt_compiler_lib_search_dirs_RC + +# The library search path used internally by the compiler when linking +# a shared library. +compiler_lib_search_path=$lt_compiler_lib_search_path_RC + +# Method to check whether dependent libraries are shared objects. +deplibs_check_method=$lt_deplibs_check_method + +# Command to use when deplibs_check_method == file_magic. +file_magic_cmd=$lt_file_magic_cmd + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$lt_allow_undefined_flag_RC + +# Flag that forces no undefined symbols. +no_undefined_flag=$lt_no_undefined_flag_RC + +# Commands used to finish a libtool library installation in a directory. +finish_cmds=$lt_finish_cmds + +# Same as above, but a single script fragment to be evaled but not shown. +finish_eval=$lt_finish_eval + +# Take the output of nm and produce a listing of raw symbols and C names. +global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe + +# Transform the output of nm in a proper C declaration +global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl + +# Transform the output of nm in a C name address pair +global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address + +# This is the shared library runtime path variable. +runpath_var=$runpath_var + +# This is the shared library path variable. +shlibpath_var=$shlibpath_var + +# Is shlibpath searched before the hard-coded library search path? +shlibpath_overrides_runpath=$shlibpath_overrides_runpath + +# How to hardcode a shared library path into an executable. +hardcode_action=$hardcode_action_RC + +# Whether we should hardcode library paths into libraries. +hardcode_into_libs=$hardcode_into_libs + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist. +hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_RC + +# If ld is used when linking, flag to hardcode \$libdir into +# a binary during linking. This must work even if \$libdir does +# not exist. +hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld_RC + +# Whether we need a single -rpath flag with a separated argument. +hardcode_libdir_separator=$lt_hardcode_libdir_separator_RC + +# Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the +# resulting binary. +hardcode_direct=$hardcode_direct_RC + +# Set to yes if using the -LDIR flag during linking hardcodes DIR into the +# resulting binary. +hardcode_minus_L=$hardcode_minus_L_RC + +# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into +# the resulting binary. +hardcode_shlibpath_var=$hardcode_shlibpath_var_RC + +# Set to yes if building a shared library automatically hardcodes DIR into the library +# and all subsequent libraries and executables linked against it. +hardcode_automatic=$hardcode_automatic_RC + +# Variables whose values should be saved in libtool wrapper scripts and +# restored at relink time. +variables_saved_for_relink="$variables_saved_for_relink" + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=$link_all_deplibs_RC + +# Compile-time system search path for libraries +sys_lib_search_path_spec=$lt_sys_lib_search_path_spec + +# Run-time system search path for libraries +sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec + +# Fix the shell variable \$srcfile for the compiler. +fix_srcfile_path=$lt_fix_srcfile_path + +# Set to yes if exported symbols are required. +always_export_symbols=$always_export_symbols_RC + +# The commands to list exported symbols. +export_symbols_cmds=$lt_export_symbols_cmds_RC + +# The commands to extract the exported symbol list from a shared archive. +extract_expsyms_cmds=$lt_extract_expsyms_cmds + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms=$lt_exclude_expsyms_RC + +# Symbols that must always be exported. +include_expsyms=$lt_include_expsyms_RC + +# ### END LIBTOOL TAG CONFIG: $tagname + +__EOF__ + + +else + # If there is no Makefile yet, we rely on a make rule to execute + # `config.status --recheck' to rerun these tests and create the + # libtool script then. + ltmain_in=`echo $ltmain | sed -e 's/\.sh$/.in/'` + if test -f "$ltmain_in"; then + test -f Makefile && make "$ltmain" + 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 + +CC="$lt_save_CC" + + ;; + + *) + { { echo "$as_me:$LINENO: error: Unsupported tag name: $tagname" >&5 +echo "$as_me: error: Unsupported tag name: $tagname" >&2;} + { (exit 1); exit 1; }; } + ;; + esac + + # Append the new tag name to the list of available tags. + if test -n "$tagname" ; then + available_tags="$available_tags $tagname" + fi + fi + done + IFS="$lt_save_ifs" + + # Now substitute the updated list of available tags. + if eval "sed -e 's/^available_tags=.*\$/available_tags=\"$available_tags\"/' \"$ofile\" > \"${ofile}T\""; then + mv "${ofile}T" "$ofile" + chmod +x "$ofile" + else + rm -f "${ofile}T" + { { echo "$as_me:$LINENO: error: unable to update list of available tagged configurations." >&5 +echo "$as_me: error: unable to update list of available tagged configurations." >&2;} + { (exit 1); exit 1; }; } + fi +fi + + + +# This can be used to rebuild libtool when needed +LIBTOOL_DEPS="$ac_aux_dir/ltmain.sh" + +# Always use our own libtool. +LIBTOOL='$(SHELL) $(top_builddir)/libtool' + +# Prevent multiple expansion + + + + + + + + + + + + + + + + + + + + + + +# Extract the first word of "mv", so it can be a program name with args. +set dummy mv; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_path_MV+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + case $MV in + [\\/]* | ?:[\\/]*) + ac_cv_path_MV="$MV" # Let the user override the test with a path. + ;; + *) + 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 { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_path_MV="$as_dir/$ac_word$ac_exec_ext" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + + ;; +esac +fi +MV=$ac_cv_path_MV +if test -n "$MV"; then + { echo "$as_me:$LINENO: result: $MV" >&5 +echo "${ECHO_T}$MV" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + +# Extract the first word of "rm", so it can be a program name with args. +set dummy rm; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_path_RM+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + case $RM in + [\\/]* | ?:[\\/]*) + ac_cv_path_RM="$RM" # Let the user override the test with a path. + ;; + *) + 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 { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_path_RM="$as_dir/$ac_word$ac_exec_ext" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + + ;; +esac +fi +RM=$ac_cv_path_RM +if test -n "$RM"; then + { echo "$as_me:$LINENO: result: $RM" >&5 +echo "${ECHO_T}$RM" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + +# Extract the first word of "sed", so it can be a program name with args. +set dummy sed; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_path_SED+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + case $SED in + [\\/]* | ?:[\\/]*) + ac_cv_path_SED="$SED" # Let the user override the test with a path. + ;; + *) + 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 { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_path_SED="$as_dir/$ac_word$ac_exec_ext" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + + ;; +esac +fi +SED=$ac_cv_path_SED +if test -n "$SED"; then + { echo "$as_me:$LINENO: result: $SED" >&5 +echo "${ECHO_T}$SED" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + + +# Extract the first word of "ldconfig", so it can be a program name with args. +set dummy ldconfig; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_path_LDCONFIG+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + case $LDCONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_LDCONFIG="$LDCONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in /sbin /usr/sbin $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_path_LDCONFIG="$as_dir/$ac_word$ac_exec_ext" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + + test -z "$ac_cv_path_LDCONFIG" && ac_cv_path_LDCONFIG="true" + ;; +esac +fi +LDCONFIG=$ac_cv_path_LDCONFIG +if test -n "$LDCONFIG"; then + { echo "$as_me:$LINENO: result: $LDCONFIG" >&5 +echo "${ECHO_T}$LDCONFIG" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + + +# Environment +{ echo "$as_me:$LINENO: checking Windows OS" >&5 +echo $ECHO_N "checking Windows OS... $ECHO_C" >&6; } +case "${target}" in +*-mingw32*|*-winnt*|*-cygwin*) + { echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } + WINDOWS="yes" + +cat >>confdefs.h <<\_ACEOF +#define WINDOWS 1 +_ACEOF + + ;; +*) + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } + WINDOWS="no" + ;; +esac + +{ echo "$as_me:$LINENO: checking fuse compatibility" >&5 +echo $ECHO_N "checking fuse compatibility... $ECHO_C" >&6; } +case "${target_os}" in +linux*) + +# Check whether --with-fuse was given. +if test "${with_fuse+set}" = set; then + withval=$with_fuse; +else + with_fuse="internal" + +fi + + ;; +darwin*|netbsd*|solaris*) + with_fuse="external" + ;; +freebsd*) + { { echo "$as_me:$LINENO: error: Please see FreeBSD support at http://www.freshports.org/sysutils/fusefs-ntfs" >&5 +echo "$as_me: error: Please see FreeBSD support at http://www.freshports.org/sysutils/fusefs-ntfs" >&2;} + { (exit 1); exit 1; }; } + ;; +*) + { { echo "$as_me:$LINENO: error: ntfs-3g can be built for Linux, FreeBSD, Mac OS X, NetBSD, and Solaris only." >&5 +echo "$as_me: error: ntfs-3g can be built for Linux, FreeBSD, Mac OS X, NetBSD, and Solaris only." >&2;} + { (exit 1); exit 1; }; } + ;; +esac +{ echo "$as_me:$LINENO: result: ${with_fuse}" >&5 +echo "${ECHO_T}${with_fuse}" >&6; } + +case "${target_os}" in +solaris*) + if test "x$GCC" != "xyes" ; then + { { echo "$as_me:$LINENO: error: ntfs-3g can be built only with gcc on Solaris. Install it by 'pkg install gcc-dev' and retry.)" >&5 +echo "$as_me: error: ntfs-3g can be built only with gcc on Solaris. Install it by 'pkg install gcc-dev' and retry.)" >&2;} + { (exit 1); exit 1; }; } + fi + ;; +esac + +if test "${enable_ldscript}" = "yes"; then + { echo "$as_me:$LINENO: checking Output format" >&5 +echo $ECHO_N "checking Output format... $ECHO_C" >&6; } + OUTPUT_FORMAT="$(${CC} ${CFLAGS} ${LDFLAGS} -Wl,--verbose 2>&1 | ${SED} -n 's/^OUTPUT_FORMAT("\([^"]*\)",.*/\1/p')" + if test -z "${OUTPUT_FORMAT}"; then + { echo "$as_me:$LINENO: result: None" >&5 +echo "${ECHO_T}None" >&6; } + else + { echo "$as_me:$LINENO: result: ${OUTPUT_FORMAT}" >&5 +echo "${ECHO_T}${OUTPUT_FORMAT}" >&6; } + OUTPUT_FORMAT="OUTPUT_FORMAT ( ${OUTPUT_FORMAT} )" + fi +fi + +# Libraries +if test "${with_fuse}" = "internal"; then + { echo "$as_me:$LINENO: checking for pthread_create in -lpthread" >&5 +echo $ECHO_N "checking for pthread_create in -lpthread... $ECHO_C" >&6; } +if test "${ac_cv_lib_pthread_pthread_create+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lpthread $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* 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 pthread_create (); +int +main () +{ +return pthread_create (); + ; + return 0; +} +_ACEOF +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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + ac_cv_lib_pthread_pthread_create=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_lib_pthread_pthread_create=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ echo "$as_me:$LINENO: result: $ac_cv_lib_pthread_pthread_create" >&5 +echo "${ECHO_T}$ac_cv_lib_pthread_pthread_create" >&6; } +if test $ac_cv_lib_pthread_pthread_create = yes; then + LIBFUSE_LITE_LIBS="${LIBFUSE_LITE_LIBS} -lpthread" +else + { { echo "$as_me:$LINENO: error: Cannot find pthread library" >&5 +echo "$as_me: error: Cannot find pthread library" >&2;} + { (exit 1); exit 1; }; } + +fi + + +cat >>confdefs.h <<\_ACEOF +#define _REENTRANT 1 +_ACEOF + + # required so that we re-compile anything + +cat >>confdefs.h <<\_ACEOF +#define FUSE_INTERNAL 1 +_ACEOF + +else + if test -z "$PKG_CONFIG"; then + # Extract the first word of "pkg-config", so it can be a program name with args. +set dummy pkg-config; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_path_PKG_CONFIG+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + case $PKG_CONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path. + ;; + *) + 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 { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + + test -z "$ac_cv_path_PKG_CONFIG" && ac_cv_path_PKG_CONFIG="no" + ;; +esac +fi +PKG_CONFIG=$ac_cv_path_PKG_CONFIG +if test -n "$PKG_CONFIG"; then + { echo "$as_me:$LINENO: result: $PKG_CONFIG" >&5 +echo "${ECHO_T}$PKG_CONFIG" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + + fi + test "x${PKG_CONFIG}" = "xno" && { { echo "$as_me:$LINENO: error: pkg-config wasn't found! Please install from your vendor, or see http://pkg-config.freedesktop.org/wiki/" >&5 +echo "$as_me: error: pkg-config wasn't found! Please install from your vendor, or see http://pkg-config.freedesktop.org/wiki/" >&2;} + { (exit 1); exit 1; }; } + # Libraries often install their metadata .pc files in directories + # not searched by pkg-config. Let's workaround this. + export PKG_CONFIG_PATH=${PKG_CONFIG_PATH}:/lib/pkgconfig:/usr/lib/pkgconfig:/opt/gnome/lib/pkgconfig:/usr/share/pkgconfig:/usr/local/lib/pkgconfig:$prefix/lib/pkgconfig:/opt/gnome/share/pkgconfig:/usr/local/share/pkgconfig + + +if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. +set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_path_PKG_CONFIG+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + case $PKG_CONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path. + ;; + *) + 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 { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + + ;; +esac +fi +PKG_CONFIG=$ac_cv_path_PKG_CONFIG +if test -n "$PKG_CONFIG"; then + { echo "$as_me:$LINENO: result: $PKG_CONFIG" >&5 +echo "${ECHO_T}$PKG_CONFIG" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + +fi +if test -z "$ac_cv_path_PKG_CONFIG"; then + ac_pt_PKG_CONFIG=$PKG_CONFIG + # Extract the first word of "pkg-config", so it can be a program name with args. +set dummy pkg-config; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_path_ac_pt_PKG_CONFIG+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + case $ac_pt_PKG_CONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path. + ;; + *) + 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 { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + + ;; +esac +fi +ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG +if test -n "$ac_pt_PKG_CONFIG"; then + { echo "$as_me:$LINENO: result: $ac_pt_PKG_CONFIG" >&5 +echo "${ECHO_T}$ac_pt_PKG_CONFIG" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + if test "x$ac_pt_PKG_CONFIG" = x; then + PKG_CONFIG="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&5 +echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&2;} +ac_tool_warned=yes ;; +esac + PKG_CONFIG=$ac_pt_PKG_CONFIG + fi +else + PKG_CONFIG="$ac_cv_path_PKG_CONFIG" +fi + +fi +if test -n "$PKG_CONFIG"; then + _pkg_min_version=0.9.0 + { echo "$as_me:$LINENO: checking pkg-config is at least version $_pkg_min_version" >&5 +echo $ECHO_N "checking pkg-config is at least version $_pkg_min_version... $ECHO_C" >&6; } + if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then + { echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } + else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } + PKG_CONFIG="" + fi + +fi + +pkg_failed=no +{ echo "$as_me:$LINENO: checking for FUSE_MODULE" >&5 +echo $ECHO_N "checking for FUSE_MODULE... $ECHO_C" >&6; } + +if test -n "$FUSE_MODULE_CFLAGS"; then + pkg_cv_FUSE_MODULE_CFLAGS="$FUSE_MODULE_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"fuse >= 2.6.0\"") >&5 + ($PKG_CONFIG --exists --print-errors "fuse >= 2.6.0") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + pkg_cv_FUSE_MODULE_CFLAGS=`$PKG_CONFIG --cflags "fuse >= 2.6.0" 2>/dev/null` +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$FUSE_MODULE_LIBS"; then + pkg_cv_FUSE_MODULE_LIBS="$FUSE_MODULE_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"fuse >= 2.6.0\"") >&5 + ($PKG_CONFIG --exists --print-errors "fuse >= 2.6.0") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + pkg_cv_FUSE_MODULE_LIBS=`$PKG_CONFIG --libs "fuse >= 2.6.0" 2>/dev/null` +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + FUSE_MODULE_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors "fuse >= 2.6.0" 2>&1` + else + FUSE_MODULE_PKG_ERRORS=`$PKG_CONFIG --print-errors "fuse >= 2.6.0" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$FUSE_MODULE_PKG_ERRORS" >&5 + + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } + + { { echo "$as_me:$LINENO: error: FUSE >= 2.6.0 was not found. Either older FUSE is still present, or FUSE is not fully installed (e.g. fuse, libfuse, libfuse2, libfuse-dev, etc packages). Source code: http://fuse.sf.net" >&5 +echo "$as_me: error: FUSE >= 2.6.0 was not found. Either older FUSE is still present, or FUSE is not fully installed (e.g. fuse, libfuse, libfuse2, libfuse-dev, etc packages). Source code: http://fuse.sf.net" >&2;} + { (exit 1); exit 1; }; } + + +elif test $pkg_failed = untried; then + + { { echo "$as_me:$LINENO: error: FUSE >= 2.6.0 was not found. Either older FUSE is still present, or FUSE is not fully installed (e.g. fuse, libfuse, libfuse2, libfuse-dev, etc packages). Source code: http://fuse.sf.net" >&5 +echo "$as_me: error: FUSE >= 2.6.0 was not found. Either older FUSE is still present, or FUSE is not fully installed (e.g. fuse, libfuse, libfuse2, libfuse-dev, etc packages). Source code: http://fuse.sf.net" >&2;} + { (exit 1); exit 1; }; } + + +else + FUSE_MODULE_CFLAGS=$pkg_cv_FUSE_MODULE_CFLAGS + FUSE_MODULE_LIBS=$pkg_cv_FUSE_MODULE_LIBS + { echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } + : +fi + FUSE_LIB_PATH=`$PKG_CONFIG --libs-only-L fuse | sed -e 's,//*,/,g' -e 's, *$,,'` +fi + +# Checks for header files. +{ echo "$as_me:$LINENO: checking for ANSI C header files" >&5 +echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6; } +if test "${ac_cv_header_stdc+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#include +#include + +int +main () +{ + + ; + return 0; +} +_ACEOF +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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_header_stdc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + 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 >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* 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 >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* 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 >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* 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 +rm -f conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +ac_cv_header_stdc=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi + + +fi +fi +{ echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5 +echo "${ECHO_T}$ac_cv_header_stdc" >&6; } +if test $ac_cv_header_stdc = yes; then + +cat >>confdefs.h <<\_ACEOF +#define STDC_HEADERS 1 +_ACEOF + +fi + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +for ac_header in ctype.h fcntl.h libgen.h libintl.h limits.h locale.h \ + mntent.h stddef.h stdint.h stdlib.h stdio.h stdarg.h string.h \ + strings.h errno.h time.h unistd.h utime.h wchar.h getopt.h features.h \ + endian.h byteswap.h sys/byteorder.h sys/endian.h sys/param.h \ + sys/ioctl.h sys/mkdev.h sys/mount.h sys/stat.h sys/types.h sys/vfs.h \ + sys/statvfs.h sys/sysmacros.h linux/major.h linux/fd.h linux/hdreg.h \ + machine/endian.h windows.h syslog.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + { echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +ac_res=`eval echo '${'$as_ac_Header'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +else + # Is the header compilable? +{ echo "$as_me:$LINENO: checking $ac_header usability" >&5 +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_compiler=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6; } + +# Is the header present? +{ echo "$as_me:$LINENO: checking $ac_header presence" >&5 +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi + +rm -f conftest.err conftest.$ac_ext +{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6; } + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + ( cat <<\_ASBOX +## ----------------------------------------- ## +## Report this to ntfs-3g-devel@lists.sf.net ## +## ----------------------------------------- ## +_ASBOX + ) | sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +{ echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +ac_res=`eval echo '${'$as_ac_Header'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } + +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +# Checks for typedefs, structures, and compiler characteristics. +{ echo "$as_me:$LINENO: checking for stdbool.h that conforms to C99" >&5 +echo $ECHO_N "checking for stdbool.h that conforms to C99... $ECHO_C" >&6; } +if test "${ac_cv_header_stdbool_h+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +#include +#ifndef bool + "error: bool is not defined" +#endif +#ifndef false + "error: false is not defined" +#endif +#if false + "error: false is not 0" +#endif +#ifndef true + "error: true is not defined" +#endif +#if true != 1 + "error: true is not 1" +#endif +#ifndef __bool_true_false_are_defined + "error: __bool_true_false_are_defined is not defined" +#endif + + struct s { _Bool s: 1; _Bool t; } s; + + char a[true == 1 ? 1 : -1]; + char b[false == 0 ? 1 : -1]; + char c[__bool_true_false_are_defined == 1 ? 1 : -1]; + char d[(bool) 0.5 == true ? 1 : -1]; + bool e = &s; + char f[(_Bool) 0.0 == false ? 1 : -1]; + char g[true]; + char h[sizeof (_Bool)]; + char i[sizeof s.t]; + enum { j = false, k = true, l = false * true, m = true * 256 }; + _Bool n[m]; + char o[sizeof n == m * sizeof n[0] ? 1 : -1]; + char p[-1 - (_Bool) 0 < 0 && -1 - (bool) 0 < 0 ? 1 : -1]; +# if defined __xlc__ || defined __GNUC__ + /* Catch a bug in IBM AIX xlc compiler version 6.0.0.0 + reported by James Lemley on 2005-10-05; see + http://lists.gnu.org/archive/html/bug-coreutils/2005-10/msg00086.html + This test is not quite right, since xlc is allowed to + reject this program, as the initializer for xlcbug is + not one of the forms that C requires support for. + However, doing the test right would require a runtime + test, and that would make cross-compilation harder. + Let us hope that IBM fixes the xlc bug, and also adds + support for this kind of constant expression. In the + meantime, this test will reject xlc, which is OK, since + our stdbool.h substitute should suffice. We also test + this with GCC, where it should work, to detect more + quickly whether someone messes up the test in the + future. */ + char digs[] = "0123456789"; + int xlcbug = 1 / (&(digs + 5)[-2 + (bool) 1] == &digs[4] ? 1 : -1); +# endif + /* Catch a bug in an HP-UX C compiler. See + http://gcc.gnu.org/ml/gcc-patches/2003-12/msg02303.html + http://lists.gnu.org/archive/html/bug-coreutils/2005-11/msg00161.html + */ + _Bool q = true; + _Bool *pq = &q; + +int +main () +{ + + *pq |= q; + *pq |= ! q; + /* Refer to every declared value, to avoid compiler optimizations. */ + return (!a + !b + !c + !d + !e + !f + !g + !h + !i + !!j + !k + !!l + + !m + !n + !o + !p + !q + !pq); + + ; + return 0; +} +_ACEOF +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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_header_stdbool_h=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_header_stdbool_h=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ac_cv_header_stdbool_h" >&5 +echo "${ECHO_T}$ac_cv_header_stdbool_h" >&6; } +{ echo "$as_me:$LINENO: checking for _Bool" >&5 +echo $ECHO_N "checking for _Bool... $ECHO_C" >&6; } +if test "${ac_cv_type__Bool+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +typedef _Bool ac__type_new_; +int +main () +{ +if ((ac__type_new_ *) 0) + return 0; +if (sizeof (ac__type_new_)) + return 0; + ; + return 0; +} +_ACEOF +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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_type__Bool=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_type__Bool=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ac_cv_type__Bool" >&5 +echo "${ECHO_T}$ac_cv_type__Bool" >&6; } +if test $ac_cv_type__Bool = yes; then + +cat >>confdefs.h <<_ACEOF +#define HAVE__BOOL 1 +_ACEOF + + +fi + +if test $ac_cv_header_stdbool_h = yes; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_STDBOOL_H 1 +_ACEOF + +fi + +{ echo "$as_me:$LINENO: checking whether byte ordering is bigendian" >&5 +echo $ECHO_N "checking whether byte ordering is bigendian... $ECHO_C" >&6; } +if test "${ac_cv_c_bigendian+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # See if sys/param.h defines the BYTE_ORDER macro. +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include + +int +main () +{ +#if ! (defined BYTE_ORDER && defined BIG_ENDIAN && defined LITTLE_ENDIAN \ + && BYTE_ORDER && BIG_ENDIAN && LITTLE_ENDIAN) + bogus endian macros +#endif + + ; + return 0; +} +_ACEOF +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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + # It does; now see whether it defined to BIG_ENDIAN or not. +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include + +int +main () +{ +#if BYTE_ORDER != BIG_ENDIAN + not big endian +#endif + + ; + return 0; +} +_ACEOF +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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_c_bigendian=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_c_bigendian=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # It does not; compile a test program. +if test "$cross_compiling" = yes; then + # try to guess the endianness by grepping values into an object file + ac_cv_c_bigendian=unknown + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +short int ascii_mm[] = { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 }; +short int ascii_ii[] = { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 }; +void _ascii () { char *s = (char *) ascii_mm; s = (char *) ascii_ii; } +short int ebcdic_ii[] = { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 }; +short int ebcdic_mm[] = { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 }; +void _ebcdic () { char *s = (char *) ebcdic_mm; s = (char *) ebcdic_ii; } +int +main () +{ + _ascii (); _ebcdic (); + ; + return 0; +} +_ACEOF +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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + if grep BIGenDianSyS conftest.$ac_objext >/dev/null ; then + ac_cv_c_bigendian=yes +fi +if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then + if test "$ac_cv_c_bigendian" = unknown; then + ac_cv_c_bigendian=no + else + # finding both strings is unlikely to happen, but who knows? + ac_cv_c_bigendian=unknown + fi +fi +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ + + /* Are we little or big endian? From Harbison&Steele. */ + union + { + long int l; + char c[sizeof (long int)]; + } u; + u.l = 1; + return u.c[sizeof (long int) - 1] == 1; + + ; + return 0; +} +_ACEOF +rm -f conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_c_bigendian=no +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +ac_cv_c_bigendian=yes +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ac_cv_c_bigendian" >&5 +echo "${ECHO_T}$ac_cv_c_bigendian" >&6; } +case $ac_cv_c_bigendian in + yes) + +cat >>confdefs.h <<\_ACEOF +#define WORDS_BIGENDIAN 1 +_ACEOF + ;; + no) + + +cat >>confdefs.h <<\_ACEOF +#define WORDS_LITTLEENDIAN 1 +_ACEOF + + + ;; + *) + { { echo "$as_me:$LINENO: error: unknown endianness +presetting ac_cv_c_bigendian=no (or yes) will help" >&5 +echo "$as_me: error: unknown endianness +presetting ac_cv_c_bigendian=no (or yes) will help" >&2;} + { (exit 1); exit 1; }; } ;; +esac + +{ echo "$as_me:$LINENO: checking for inline" >&5 +echo $ECHO_N "checking for inline... $ECHO_C" >&6; } +if test "${ac_cv_c_inline+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_c_inline=no +for ac_kw in inline __inline__ __inline; do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifndef __cplusplus +typedef int foo_t; +static $ac_kw foo_t static_foo () {return 0; } +$ac_kw foo_t foo () {return 0; } +#endif + +_ACEOF +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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_c_inline=$ac_kw +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + test "$ac_cv_c_inline" != no && break +done + +fi +{ echo "$as_me:$LINENO: result: $ac_cv_c_inline" >&5 +echo "${ECHO_T}$ac_cv_c_inline" >&6; } + + +case $ac_cv_c_inline in + inline | yes) ;; + *) + case $ac_cv_c_inline in + no) ac_val=;; + *) ac_val=$ac_cv_c_inline;; + esac + cat >>confdefs.h <<_ACEOF +#ifndef __cplusplus +#define inline $ac_val +#endif +_ACEOF + ;; +esac + +{ echo "$as_me:$LINENO: checking for off_t" >&5 +echo $ECHO_N "checking for off_t... $ECHO_C" >&6; } +if test "${ac_cv_type_off_t+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +typedef off_t ac__type_new_; +int +main () +{ +if ((ac__type_new_ *) 0) + return 0; +if (sizeof (ac__type_new_)) + return 0; + ; + return 0; +} +_ACEOF +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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_type_off_t=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_type_off_t=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ac_cv_type_off_t" >&5 +echo "${ECHO_T}$ac_cv_type_off_t" >&6; } +if test $ac_cv_type_off_t = yes; then + : +else + +cat >>confdefs.h <<_ACEOF +#define off_t long int +_ACEOF + +fi + +{ echo "$as_me:$LINENO: checking for size_t" >&5 +echo $ECHO_N "checking for size_t... $ECHO_C" >&6; } +if test "${ac_cv_type_size_t+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +typedef size_t ac__type_new_; +int +main () +{ +if ((ac__type_new_ *) 0) + return 0; +if (sizeof (ac__type_new_)) + return 0; + ; + return 0; +} +_ACEOF +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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_type_size_t=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_type_size_t=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ac_cv_type_size_t" >&5 +echo "${ECHO_T}$ac_cv_type_size_t" >&6; } +if test $ac_cv_type_size_t = yes; then + : +else + +cat >>confdefs.h <<_ACEOF +#define size_t unsigned int +_ACEOF + +fi + +{ echo "$as_me:$LINENO: checking for struct stat.st_blocks" >&5 +echo $ECHO_N "checking for struct stat.st_blocks... $ECHO_C" >&6; } +if test "${ac_cv_member_struct_stat_st_blocks+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static struct stat ac_aggr; +if (ac_aggr.st_blocks) +return 0; + ; + return 0; +} +_ACEOF +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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_member_struct_stat_st_blocks=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static struct stat ac_aggr; +if (sizeof ac_aggr.st_blocks) +return 0; + ; + return 0; +} +_ACEOF +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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_member_struct_stat_st_blocks=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_member_struct_stat_st_blocks=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 +{ echo "$as_me:$LINENO: result: $ac_cv_member_struct_stat_st_blocks" >&5 +echo "${ECHO_T}$ac_cv_member_struct_stat_st_blocks" >&6; } +if test $ac_cv_member_struct_stat_st_blocks = yes; then + +cat >>confdefs.h <<_ACEOF +#define HAVE_STRUCT_STAT_ST_BLOCKS 1 +_ACEOF + + +cat >>confdefs.h <<\_ACEOF +#define HAVE_ST_BLOCKS 1 +_ACEOF + +else + case " $LIBOBJS " in + *" fileblocks.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS fileblocks.$ac_objext" + ;; +esac + +fi + + +{ echo "$as_me:$LINENO: checking for struct stat.st_rdev" >&5 +echo $ECHO_N "checking for struct stat.st_rdev... $ECHO_C" >&6; } +if test "${ac_cv_member_struct_stat_st_rdev+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static struct stat ac_aggr; +if (ac_aggr.st_rdev) +return 0; + ; + return 0; +} +_ACEOF +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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_member_struct_stat_st_rdev=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static struct stat ac_aggr; +if (sizeof ac_aggr.st_rdev) +return 0; + ; + return 0; +} +_ACEOF +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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_member_struct_stat_st_rdev=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_member_struct_stat_st_rdev=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 +{ echo "$as_me:$LINENO: result: $ac_cv_member_struct_stat_st_rdev" >&5 +echo "${ECHO_T}$ac_cv_member_struct_stat_st_rdev" >&6; } +if test $ac_cv_member_struct_stat_st_rdev = yes; then + +cat >>confdefs.h <<_ACEOF +#define HAVE_STRUCT_STAT_ST_RDEV 1 +_ACEOF + + +fi + +{ echo "$as_me:$LINENO: checking for struct stat.st_atim" >&5 +echo $ECHO_N "checking for struct stat.st_atim... $ECHO_C" >&6; } +if test "${ac_cv_member_struct_stat_st_atim+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static struct stat ac_aggr; +if (ac_aggr.st_atim) +return 0; + ; + return 0; +} +_ACEOF +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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_member_struct_stat_st_atim=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static struct stat ac_aggr; +if (sizeof ac_aggr.st_atim) +return 0; + ; + return 0; +} +_ACEOF +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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_member_struct_stat_st_atim=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_member_struct_stat_st_atim=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 +{ echo "$as_me:$LINENO: result: $ac_cv_member_struct_stat_st_atim" >&5 +echo "${ECHO_T}$ac_cv_member_struct_stat_st_atim" >&6; } +if test $ac_cv_member_struct_stat_st_atim = yes; then + +cat >>confdefs.h <<_ACEOF +#define HAVE_STRUCT_STAT_ST_ATIM 1 +_ACEOF + + +fi + +{ echo "$as_me:$LINENO: checking for struct stat.st_atimespec" >&5 +echo $ECHO_N "checking for struct stat.st_atimespec... $ECHO_C" >&6; } +if test "${ac_cv_member_struct_stat_st_atimespec+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static struct stat ac_aggr; +if (ac_aggr.st_atimespec) +return 0; + ; + return 0; +} +_ACEOF +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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_member_struct_stat_st_atimespec=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static struct stat ac_aggr; +if (sizeof ac_aggr.st_atimespec) +return 0; + ; + return 0; +} +_ACEOF +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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_member_struct_stat_st_atimespec=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_member_struct_stat_st_atimespec=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 +{ echo "$as_me:$LINENO: result: $ac_cv_member_struct_stat_st_atimespec" >&5 +echo "${ECHO_T}$ac_cv_member_struct_stat_st_atimespec" >&6; } +if test $ac_cv_member_struct_stat_st_atimespec = yes; then + +cat >>confdefs.h <<_ACEOF +#define HAVE_STRUCT_STAT_ST_ATIMESPEC 1 +_ACEOF + + +fi + +{ echo "$as_me:$LINENO: checking for struct stat.st_atimensec" >&5 +echo $ECHO_N "checking for struct stat.st_atimensec... $ECHO_C" >&6; } +if test "${ac_cv_member_struct_stat_st_atimensec+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static struct stat ac_aggr; +if (ac_aggr.st_atimensec) +return 0; + ; + return 0; +} +_ACEOF +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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_member_struct_stat_st_atimensec=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static struct stat ac_aggr; +if (sizeof ac_aggr.st_atimensec) +return 0; + ; + return 0; +} +_ACEOF +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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_member_struct_stat_st_atimensec=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_member_struct_stat_st_atimensec=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 +{ echo "$as_me:$LINENO: result: $ac_cv_member_struct_stat_st_atimensec" >&5 +echo "${ECHO_T}$ac_cv_member_struct_stat_st_atimensec" >&6; } +if test $ac_cv_member_struct_stat_st_atimensec = yes; then + +cat >>confdefs.h <<_ACEOF +#define HAVE_STRUCT_STAT_ST_ATIMENSEC 1 +_ACEOF + + +fi + + +# For the 'nfconv' patch (Mac OS X only): +case "${target_os}" in +darwin*) + if test "${enable_nfconv}" = "yes"; then + if test "${ac_cv_header_CoreFoundation_CoreFoundation_h+set}" = set; then + { echo "$as_me:$LINENO: checking for CoreFoundation/CoreFoundation.h" >&5 +echo $ECHO_N "checking for CoreFoundation/CoreFoundation.h... $ECHO_C" >&6; } +if test "${ac_cv_header_CoreFoundation_CoreFoundation_h+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +{ echo "$as_me:$LINENO: result: $ac_cv_header_CoreFoundation_CoreFoundation_h" >&5 +echo "${ECHO_T}$ac_cv_header_CoreFoundation_CoreFoundation_h" >&6; } +else + # Is the header compilable? +{ echo "$as_me:$LINENO: checking CoreFoundation/CoreFoundation.h usability" >&5 +echo $ECHO_N "checking CoreFoundation/CoreFoundation.h usability... $ECHO_C" >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include +_ACEOF +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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_compiler=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6; } + +# Is the header present? +{ echo "$as_me:$LINENO: checking CoreFoundation/CoreFoundation.h presence" >&5 +echo $ECHO_N "checking CoreFoundation/CoreFoundation.h presence... $ECHO_C" >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi + +rm -f conftest.err conftest.$ac_ext +{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6; } + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: CoreFoundation/CoreFoundation.h: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: CoreFoundation/CoreFoundation.h: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: CoreFoundation/CoreFoundation.h: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: CoreFoundation/CoreFoundation.h: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: CoreFoundation/CoreFoundation.h: present but cannot be compiled" >&5 +echo "$as_me: WARNING: CoreFoundation/CoreFoundation.h: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: CoreFoundation/CoreFoundation.h: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: CoreFoundation/CoreFoundation.h: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: CoreFoundation/CoreFoundation.h: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: CoreFoundation/CoreFoundation.h: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: CoreFoundation/CoreFoundation.h: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: CoreFoundation/CoreFoundation.h: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: CoreFoundation/CoreFoundation.h: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: CoreFoundation/CoreFoundation.h: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: CoreFoundation/CoreFoundation.h: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: CoreFoundation/CoreFoundation.h: in the future, the compiler will take precedence" >&2;} + ( cat <<\_ASBOX +## ----------------------------------------- ## +## Report this to ntfs-3g-devel@lists.sf.net ## +## ----------------------------------------- ## +_ASBOX + ) | sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +{ echo "$as_me:$LINENO: checking for CoreFoundation/CoreFoundation.h" >&5 +echo $ECHO_N "checking for CoreFoundation/CoreFoundation.h... $ECHO_C" >&6; } +if test "${ac_cv_header_CoreFoundation_CoreFoundation_h+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_header_CoreFoundation_CoreFoundation_h=$ac_header_preproc +fi +{ echo "$as_me:$LINENO: result: $ac_cv_header_CoreFoundation_CoreFoundation_h" >&5 +echo "${ECHO_T}$ac_cv_header_CoreFoundation_CoreFoundation_h" >&6; } + +fi +if test $ac_cv_header_CoreFoundation_CoreFoundation_h = yes; then + + LDFLAGS="${LDFLAGS} -framework CoreFoundation" + +cat >>confdefs.h <<\_ACEOF +#define ENABLE_NFCONV 1 +_ACEOF + + +else + { { echo "$as_me:$LINENO: error: Cannot find CoreFoundation required for 'nfconv' functionality Mac OS X. You may use the --disable-nfconv 'configure' option to avoid this error." >&5 +echo "$as_me: error: Cannot find CoreFoundation required for 'nfconv' functionality Mac OS X. You may use the --disable-nfconv 'configure' option to avoid this error." >&2;} + { (exit 1); exit 1; }; } + +fi + + + fi + ;; +esac + +# Checks for library functions. +# getmntent is in the standard C library on UNICOS, in -lsun on Irix 4, +# -lseq on Dynix/PTX, -lgen on Unixware. +{ echo "$as_me:$LINENO: checking for library containing getmntent" >&5 +echo $ECHO_N "checking for library containing getmntent... $ECHO_C" >&6; } +if test "${ac_cv_search_getmntent+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_func_search_save_LIBS=$LIBS +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* 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 getmntent (); +int +main () +{ +return getmntent (); + ; + return 0; +} +_ACEOF +for ac_lib in '' sun seq gen; do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + fi + 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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + ac_cv_search_getmntent=$ac_res +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext + if test "${ac_cv_search_getmntent+set}" = set; then + break +fi +done +if test "${ac_cv_search_getmntent+set}" = set; then + : +else + ac_cv_search_getmntent=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ echo "$as_me:$LINENO: result: $ac_cv_search_getmntent" >&5 +echo "${ECHO_T}$ac_cv_search_getmntent" >&6; } +ac_res=$ac_cv_search_getmntent +if test "$ac_res" != no; then + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + ac_cv_func_getmntent=yes + +cat >>confdefs.h <<\_ACEOF +#define HAVE_GETMNTENT +_ACEOF + +else + ac_cv_func_getmntent=no +fi + + + + { echo "$as_me:$LINENO: checking whether mbrtowc and mbstate_t are properly declared" >&5 +echo $ECHO_N "checking whether mbrtowc and mbstate_t are properly declared... $ECHO_C" >&6; } +if test "${ac_cv_func_mbrtowc+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +int +main () +{ +wchar_t wc; + char const s[] = ""; + size_t n = 1; + mbstate_t state; + return ! (sizeof state && (mbrtowc) (&wc, s, n, &state)); + ; + return 0; +} +_ACEOF +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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + ac_cv_func_mbrtowc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_func_mbrtowc=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ac_cv_func_mbrtowc" >&5 +echo "${ECHO_T}$ac_cv_func_mbrtowc" >&6; } + if test $ac_cv_func_mbrtowc = yes; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_MBRTOWC 1 +_ACEOF + + fi + +{ echo "$as_me:$LINENO: checking for working memcmp" >&5 +echo $ECHO_N "checking for working memcmp... $ECHO_C" >&6; } +if test "${ac_cv_func_memcmp_working+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test "$cross_compiling" = yes; then + ac_cv_func_memcmp_working=no +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ + + /* Some versions of memcmp are not 8-bit clean. */ + char c0 = '\100', c1 = '\200', c2 = '\201'; + if (memcmp(&c0, &c2, 1) >= 0 || memcmp(&c1, &c2, 1) >= 0) + return 1; + + /* The Next x86 OpenStep bug shows up only when comparing 16 bytes + or more and with at least one buffer not starting on a 4-byte boundary. + William Lewis provided this test program. */ + { + char foo[21]; + char bar[21]; + int i; + for (i = 0; i < 4; i++) + { + char *a = foo + i; + char *b = bar + i; + strcpy (a, "--------01111111"); + strcpy (b, "--------10000000"); + if (memcmp (a, b, 16) >= 0) + return 1; + } + return 0; + } + + ; + return 0; +} +_ACEOF +rm -f conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_func_memcmp_working=yes +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +ac_cv_func_memcmp_working=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi + + +fi +{ echo "$as_me:$LINENO: result: $ac_cv_func_memcmp_working" >&5 +echo "${ECHO_T}$ac_cv_func_memcmp_working" >&6; } +test $ac_cv_func_memcmp_working = no && case " $LIBOBJS " in + *" memcmp.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS memcmp.$ac_objext" + ;; +esac + + +{ echo "$as_me:$LINENO: checking whether lstat dereferences a symlink specified with a trailing slash" >&5 +echo $ECHO_N "checking whether lstat dereferences a symlink specified with a trailing slash... $ECHO_C" >&6; } +if test "${ac_cv_func_lstat_dereferences_slashed_symlink+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&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 >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +struct stat sbuf; + /* Linux will dereference the symlink and fail. + 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 +rm -f conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_func_lstat_dereferences_slashed_symlink=yes +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +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.$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 +{ echo "$as_me:$LINENO: result: $ac_cv_func_lstat_dereferences_slashed_symlink" >&5 +echo "${ECHO_T}$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 $ac_cv_func_lstat_dereferences_slashed_symlink = no; then + case " $LIBOBJS " in + *" lstat.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS lstat.$ac_objext" + ;; +esac + +fi + +{ echo "$as_me:$LINENO: checking whether stat accepts an empty string" >&5 +echo $ECHO_N "checking whether stat accepts an empty string... $ECHO_C" >&6; } +if test "${ac_cv_func_stat_empty_string_bug+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test "$cross_compiling" = yes; then + ac_cv_func_stat_empty_string_bug=yes +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +struct stat sbuf; + return stat ("", &sbuf) == 0; + ; + return 0; +} +_ACEOF +rm -f conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_func_stat_empty_string_bug=no +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +ac_cv_func_stat_empty_string_bug=yes +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi + + +fi +{ echo "$as_me:$LINENO: result: $ac_cv_func_stat_empty_string_bug" >&5 +echo "${ECHO_T}$ac_cv_func_stat_empty_string_bug" >&6; } +if test $ac_cv_func_stat_empty_string_bug = yes; then + case " $LIBOBJS " in + *" stat.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS stat.$ac_objext" + ;; +esac + + +cat >>confdefs.h <<_ACEOF +#define HAVE_STAT_EMPTY_STRING_BUG 1 +_ACEOF + +fi + + +for ac_func in strftime +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +{ echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; } +if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case declares $ac_func. + For example, HP-UX 11i declares gettimeofday. */ +#define $ac_func innocuous_$ac_func + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $ac_func + +/* 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 $ac_func (); +/* 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_$ac_func || defined __stub___$ac_func +choke me +#endif + +int +main () +{ +return $ac_func (); + ; + return 0; +} +_ACEOF +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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + eval "$as_ac_var=no" +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +fi +ac_res=`eval echo '${'$as_ac_var'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +else + # strftime is in -lintl on SCO UNIX. +{ echo "$as_me:$LINENO: checking for strftime in -lintl" >&5 +echo $ECHO_N "checking for strftime in -lintl... $ECHO_C" >&6; } +if test "${ac_cv_lib_intl_strftime+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lintl $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* 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 strftime (); +int +main () +{ +return strftime (); + ; + return 0; +} +_ACEOF +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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + ac_cv_lib_intl_strftime=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_lib_intl_strftime=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ echo "$as_me:$LINENO: result: $ac_cv_lib_intl_strftime" >&5 +echo "${ECHO_T}$ac_cv_lib_intl_strftime" >&6; } +if test $ac_cv_lib_intl_strftime = yes; then + cat >>confdefs.h <<\_ACEOF +#define HAVE_STRFTIME 1 +_ACEOF + +LIBS="-lintl $LIBS" +fi + +fi +done + + + + + +for ac_header in $ac_header_list +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + { echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +ac_res=`eval echo '${'$as_ac_Header'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +else + # Is the header compilable? +{ echo "$as_me:$LINENO: checking $ac_header usability" >&5 +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_compiler=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6; } + +# Is the header present? +{ echo "$as_me:$LINENO: checking $ac_header presence" >&5 +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi + +rm -f conftest.err conftest.$ac_ext +{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6; } + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + ( cat <<\_ASBOX +## ----------------------------------------- ## +## Report this to ntfs-3g-devel@lists.sf.net ## +## ----------------------------------------- ## +_ASBOX + ) | sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +{ echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +ac_res=`eval echo '${'$as_ac_Header'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } + +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + + + + + + + + +{ echo "$as_me:$LINENO: checking whether utime accepts a null argument" >&5 +echo $ECHO_N "checking whether utime accepts a null argument... $ECHO_C" >&6; } +if test "${ac_cv_func_utime_null+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + rm -f conftest.data; >conftest.data +# Sequent interprets utime(file, 0) to mean use start of epoch. Wrong. +if test "$cross_compiling" = yes; then + ac_cv_func_utime_null=no +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + #ifdef HAVE_UTIME_H + # include + #endif +int +main () +{ +struct stat s, t; + return ! (stat ("conftest.data", &s) == 0 + && utime ("conftest.data", 0) == 0 + && stat ("conftest.data", &t) == 0 + && t.st_mtime >= s.st_mtime + && t.st_mtime - s.st_mtime < 120); + ; + return 0; +} +_ACEOF +rm -f conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_func_utime_null=yes +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +ac_cv_func_utime_null=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi + + +fi +{ echo "$as_me:$LINENO: result: $ac_cv_func_utime_null" >&5 +echo "${ECHO_T}$ac_cv_func_utime_null" >&6; } +if test $ac_cv_func_utime_null = yes; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_UTIME_NULL 1 +_ACEOF + +fi +rm -f conftest.data + + +for ac_func in vprintf +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +{ echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; } +if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case declares $ac_func. + For example, HP-UX 11i declares gettimeofday. */ +#define $ac_func innocuous_$ac_func + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $ac_func + +/* 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 $ac_func (); +/* 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_$ac_func || defined __stub___$ac_func +choke me +#endif + +int +main () +{ +return $ac_func (); + ; + return 0; +} +_ACEOF +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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + eval "$as_ac_var=no" +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +fi +ac_res=`eval echo '${'$as_ac_var'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +{ echo "$as_me:$LINENO: checking for _doprnt" >&5 +echo $ECHO_N "checking for _doprnt... $ECHO_C" >&6; } +if test "${ac_cv_func__doprnt+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define _doprnt to an innocuous variant, in case declares _doprnt. + For example, HP-UX 11i declares gettimeofday. */ +#define _doprnt innocuous__doprnt + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char _doprnt (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef _doprnt + +/* 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 _doprnt (); +/* 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__doprnt || defined __stub____doprnt +choke me +#endif + +int +main () +{ +return _doprnt (); + ; + return 0; +} +_ACEOF +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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + ac_cv_func__doprnt=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_func__doprnt=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ac_cv_func__doprnt" >&5 +echo "${ECHO_T}$ac_cv_func__doprnt" >&6; } +if test $ac_cv_func__doprnt = yes; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_DOPRNT 1 +_ACEOF + +fi + +fi +done + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +for ac_func in \ + atexit basename daemon dup2 fdatasync ffs getopt_long hasmntopt \ + mbsinit memmove memset realpath regcomp setlocale setxattr \ + strcasecmp strchr strdup strerror strnlen strsep strtol strtoul \ + sysconf utime utimensat gettimeofday clock_gettime fork \ + +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +{ echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; } +if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case declares $ac_func. + For example, HP-UX 11i declares gettimeofday. */ +#define $ac_func innocuous_$ac_func + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $ac_func + +/* 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 $ac_func (); +/* 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_$ac_func || defined __stub___$ac_func +choke me +#endif + +int +main () +{ +return $ac_func (); + ; + return 0; +} +_ACEOF +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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + eval "$as_ac_var=no" +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +fi +ac_res=`eval echo '${'$as_ac_var'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + +# Check whether --enable-largefile was given. +if test "${enable_largefile+set}" = set; then + enableval=$enable_largefile; +fi + +if test "$enable_largefile" != no; then + + { echo "$as_me:$LINENO: checking for special C compiler options needed for large files" >&5 +echo $ECHO_N "checking for special C compiler options needed for large files... $ECHO_C" >&6; } +if test "${ac_cv_sys_largefile_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_sys_largefile_CC=no + if test "$GCC" != yes; then + ac_save_CC=$CC + while :; do + # IRIX 6.2 and later do not support large files by default, + # so use the C compiler's -n32 option if that helps. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main () +{ + + ; + return 0; +} +_ACEOF + 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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext + CC="$CC -n32" + 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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_sys_largefile_CC=' -n32'; break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext + break + done + CC=$ac_save_CC + rm -f conftest.$ac_ext + fi +fi +{ echo "$as_me:$LINENO: result: $ac_cv_sys_largefile_CC" >&5 +echo "${ECHO_T}$ac_cv_sys_largefile_CC" >&6; } + if test "$ac_cv_sys_largefile_CC" != no; then + CC=$CC$ac_cv_sys_largefile_CC + fi + + { echo "$as_me:$LINENO: checking for _FILE_OFFSET_BITS value needed for large files" >&5 +echo $ECHO_N "checking for _FILE_OFFSET_BITS value needed for large files... $ECHO_C" >&6; } +if test "${ac_cv_sys_file_offset_bits+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + while :; do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main () +{ + + ; + return 0; +} +_ACEOF +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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_sys_file_offset_bits=no; break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#define _FILE_OFFSET_BITS 64 +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main () +{ + + ; + return 0; +} +_ACEOF +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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_sys_file_offset_bits=64; break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_cv_sys_file_offset_bits=unknown + break +done +fi +{ echo "$as_me:$LINENO: result: $ac_cv_sys_file_offset_bits" >&5 +echo "${ECHO_T}$ac_cv_sys_file_offset_bits" >&6; } +case $ac_cv_sys_file_offset_bits in #( + no | unknown) ;; + *) +cat >>confdefs.h <<_ACEOF +#define _FILE_OFFSET_BITS $ac_cv_sys_file_offset_bits +_ACEOF +;; +esac +rm -f conftest* + if test $ac_cv_sys_file_offset_bits = unknown; then + { echo "$as_me:$LINENO: checking for _LARGE_FILES value needed for large files" >&5 +echo $ECHO_N "checking for _LARGE_FILES value needed for large files... $ECHO_C" >&6; } +if test "${ac_cv_sys_large_files+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + while :; do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main () +{ + + ; + return 0; +} +_ACEOF +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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_sys_large_files=no; break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#define _LARGE_FILES 1 +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main () +{ + + ; + return 0; +} +_ACEOF +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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_sys_large_files=1; break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_cv_sys_large_files=unknown + break +done +fi +{ echo "$as_me:$LINENO: result: $ac_cv_sys_large_files" >&5 +echo "${ECHO_T}$ac_cv_sys_large_files" >&6; } +case $ac_cv_sys_large_files in #( + no | unknown) ;; + *) +cat >>confdefs.h <<_ACEOF +#define _LARGE_FILES $ac_cv_sys_large_files +_ACEOF +;; +esac +rm -f conftest* + fi +fi + + +if test "$GCC" = "yes" ; then + # We add -Wall to enable some compiler warnings. + CFLAGS="${CFLAGS} -Wall" +fi + +if test "${enable_pedantic}" = "yes"; then + enable_warnings="yes" + CFLAGS="${CFLAGS} -pedantic" +fi + +if test "${enable_warnings}" = "yes"; then + CFLAGS="${CFLAGS} -W -Wall -Waggregate-return -Wbad-function-cast -Wcast-align -Wcast-qual -Wdisabled-optimization -Wdiv-by-zero -Wfloat-equal -Winline -Wmissing-declarations -Wmissing-format-attribute -Wmissing-noreturn -Wmissing-prototypes -Wmultichar -Wnested-externs -Wpointer-arith -Wredundant-decls -Wshadow -Wsign-compare -Wstrict-prototypes -Wundef -Wwrite-strings -Wformat -Wformat-security -Wuninitialized" +fi + +if test "${enable_debug}" = "yes"; then + CFLAGS="${CFLAGS} -ggdb3 -DDEBUG" + +cat >>confdefs.h <<\_ACEOF +#define ENABLE_DEBUG 1 +_ACEOF + +fi + +test "${enable_device_default_io_ops}" = "no" && +cat >>confdefs.h <<\_ACEOF +#define NO_NTFS_DEVICE_DEFAULT_IO_OPS 1 +_ACEOF + + +test "${enable_mtab}" = "no" && +cat >>confdefs.h <<\_ACEOF +#define IGNORE_MTAB 1 +_ACEOF + +test "${enable_posix_acls}" != "no" && +cat >>confdefs.h <<\_ACEOF +#define POSIXACLS 1 +_ACEOF + + +test "${enable_really_static}" = "yes" && enable_library="no" +test "${enable_library}" = "no" && enable_ldconfig="no" + +if test "x${DISTCHECK_HACK}" != "x"; then + enable_mount_helper="no" + enable_ldconfig="no" +fi + +# Settings +pkgconfigdir="\$(libdir)/pkgconfig" +ntfs3gincludedir="\$(includedir)/ntfs-3g" +# Executables should be installed to the root filesystem, otherwise +# automounting NTFS volumes can fail during boot if the driver binaries +# and their dependencies are on an unmounted partition. Use --exec-prefix +# to override this. +if test "x${exec_prefix}" = "xNONE"; then + rootbindir="/bin" + rootsbindir="/sbin" + rootlibdir="/lib${libdir##*/lib}" +else + rootbindir="\$(bindir)" + rootsbindir="\$(sbindir)" + rootlibdir="\$(libdir)" +fi + + + + + + + + + if test "${with_fuse}" = "internal"; then + FUSE_INTERNAL_TRUE= + FUSE_INTERNAL_FALSE='#' +else + FUSE_INTERNAL_TRUE='#' + FUSE_INTERNAL_FALSE= +fi + + if test "${enable_ldscript}" = "yes"; then + GENERATE_LDSCRIPT_TRUE= + GENERATE_LDSCRIPT_FALSE='#' +else + GENERATE_LDSCRIPT_TRUE='#' + GENERATE_LDSCRIPT_FALSE= +fi + + if test "${WINDOWS}" = "yes"; then + WINDOWS_TRUE= + WINDOWS_FALSE='#' +else + WINDOWS_TRUE='#' + WINDOWS_FALSE= +fi + + if test "${enable_device_default_io_ops}" = "yes"; then + NTFS_DEVICE_DEFAULT_IO_OPS_TRUE= + NTFS_DEVICE_DEFAULT_IO_OPS_FALSE='#' +else + NTFS_DEVICE_DEFAULT_IO_OPS_TRUE='#' + NTFS_DEVICE_DEFAULT_IO_OPS_FALSE= +fi + + if test "${enable_ldconfig}" = "yes"; then + RUN_LDCONFIG_TRUE= + RUN_LDCONFIG_FALSE='#' +else + RUN_LDCONFIG_TRUE='#' + RUN_LDCONFIG_FALSE= +fi + + if test "${enable_really_static}" = "yes"; then + REALLYSTATIC_TRUE= + REALLYSTATIC_FALSE='#' +else + REALLYSTATIC_TRUE='#' + REALLYSTATIC_FALSE= +fi + + if test "${enable_library}" = "yes"; then + INSTALL_LIBRARY_TRUE= + INSTALL_LIBRARY_FALSE='#' +else + INSTALL_LIBRARY_TRUE='#' + INSTALL_LIBRARY_FALSE= +fi + + if test "${enable_mount_helper}" = "yes"; then + ENABLE_MOUNT_HELPER_TRUE= + ENABLE_MOUNT_HELPER_FALSE='#' +else + ENABLE_MOUNT_HELPER_TRUE='#' + ENABLE_MOUNT_HELPER_FALSE= +fi + + +# workaround for 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_*) { echo "$as_me:$LINENO: WARNING: Cache variable $ac_var contains a newline." >&5 +echo "$as_me: WARNING: Cache variable $ac_var contains a newline." >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + *) $as_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 + test "x$cache_file" != "x/dev/null" && + { echo "$as_me:$LINENO: updating cache $cache_file" >&5 +echo "$as_me: updating cache $cache_file" >&6;} + cat confcache >$cache_file + else + { echo "$as_me:$LINENO: not updating unwritable cache $cache_file" >&5 +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= +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=`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. + ac_libobjs="$ac_libobjs \${LIBOBJDIR}$ac_i\$U.$ac_objext" + ac_ltlibobjs="$ac_ltlibobjs \${LIBOBJDIR}$ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + +if test -z "${MAINTAINER_MODE_TRUE}" && test -z "${MAINTAINER_MODE_FALSE}"; then + { { echo "$as_me:$LINENO: error: conditional \"MAINTAINER_MODE\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +echo "$as_me: error: conditional \"MAINTAINER_MODE\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi +if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then + { { echo "$as_me:$LINENO: error: conditional \"AMDEP\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +echo "$as_me: error: conditional \"AMDEP\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi +if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then + { { echo "$as_me:$LINENO: error: conditional \"am__fastdepCC\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +echo "$as_me: error: conditional \"am__fastdepCC\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi +if test -z "${am__fastdepCXX_TRUE}" && test -z "${am__fastdepCXX_FALSE}"; then + { { echo "$as_me:$LINENO: error: conditional \"am__fastdepCXX\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +echo "$as_me: error: conditional \"am__fastdepCXX\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi +if test -z "${FUSE_INTERNAL_TRUE}" && test -z "${FUSE_INTERNAL_FALSE}"; then + { { echo "$as_me:$LINENO: error: conditional \"FUSE_INTERNAL\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +echo "$as_me: error: conditional \"FUSE_INTERNAL\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi +if test -z "${GENERATE_LDSCRIPT_TRUE}" && test -z "${GENERATE_LDSCRIPT_FALSE}"; then + { { echo "$as_me:$LINENO: error: conditional \"GENERATE_LDSCRIPT\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +echo "$as_me: error: conditional \"GENERATE_LDSCRIPT\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi +if test -z "${WINDOWS_TRUE}" && test -z "${WINDOWS_FALSE}"; then + { { echo "$as_me:$LINENO: error: conditional \"WINDOWS\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +echo "$as_me: error: conditional \"WINDOWS\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi +if test -z "${NTFS_DEVICE_DEFAULT_IO_OPS_TRUE}" && test -z "${NTFS_DEVICE_DEFAULT_IO_OPS_FALSE}"; then + { { echo "$as_me:$LINENO: error: conditional \"NTFS_DEVICE_DEFAULT_IO_OPS\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +echo "$as_me: error: conditional \"NTFS_DEVICE_DEFAULT_IO_OPS\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi +if test -z "${RUN_LDCONFIG_TRUE}" && test -z "${RUN_LDCONFIG_FALSE}"; then + { { echo "$as_me:$LINENO: error: conditional \"RUN_LDCONFIG\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +echo "$as_me: error: conditional \"RUN_LDCONFIG\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi +if test -z "${REALLYSTATIC_TRUE}" && test -z "${REALLYSTATIC_FALSE}"; then + { { echo "$as_me:$LINENO: error: conditional \"REALLYSTATIC\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +echo "$as_me: error: conditional \"REALLYSTATIC\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi +if test -z "${INSTALL_LIBRARY_TRUE}" && test -z "${INSTALL_LIBRARY_FALSE}"; then + { { echo "$as_me:$LINENO: error: conditional \"INSTALL_LIBRARY\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +echo "$as_me: error: conditional \"INSTALL_LIBRARY\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi +if test -z "${ENABLE_MOUNT_HELPER_TRUE}" && test -z "${ENABLE_MOUNT_HELPER_FALSE}"; then + { { echo "$as_me:$LINENO: error: conditional \"ENABLE_MOUNT_HELPER\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +echo "$as_me: error: conditional \"ENABLE_MOUNT_HELPER\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi + +: ${CONFIG_STATUS=./config.status} +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5 +echo "$as_me: creating $CONFIG_STATUS" >&6;} +cat >$CONFIG_STATUS <<_ACEOF +#! $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} +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +## --------------------- ## +## 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=: + # Zsh 3.x and 4.x performs 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 + + + + +# PATH needs CR +# 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 + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi + +# Support unset when possible. +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +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.) +as_nl=' +' +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +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 + echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + { (exit 1); exit 1; } +fi + +# Work around bugs in pre-3.0 UWIN ksh. +for as_var in ENV MAIL MAILPATH +do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +for as_var in \ + LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ + LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ + LC_TELEPHONE LC_TIME +do + if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then + eval $as_var=C; export $as_var + else + ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var + fi +done + +# Required to use basename. +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 + + +# Name of the executable. +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# CDPATH. +$as_unset CDPATH + + + + as_lineno_1=$LINENO + as_lineno_2=$LINENO + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || { + + # Create $as_me.lineno as a copy of $as_myself, but with $LINENO + # uniformly replaced by the line number. The first 'sed' inserts a + # line-number line after each line using $LINENO; the second 'sed' + # does the real work. The second script uses 'N' to pair each + # line-number line with the line containing $LINENO, and appends + # trailing '-' during substitution so that $LINENO is not a special + # case at line end. + # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the + # scripts with optimization help from Paolo Bonzini. 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" || + { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 + { (exit 1); exit 1; }; } + + # 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 +} + + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in +-n*) + case `echo 'x\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + *) ECHO_C='\c';; + esac;; +*) + ECHO_N='-n';; +esac + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +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 +fi +echo >conf$$.file +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 -p'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -p' +elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln +else + as_ln_s='cp -p' +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=: +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +if test -x / >/dev/null 2>&1; then + as_test_x='test -x' +else + if ls -dL / >/dev/null 2>&1; then + as_ls_L_option=L + else + as_ls_L_option= + fi + as_test_x=' + eval sh -c '\'' + if test -d "$1"; then + test -d "$1/."; + else + case $1 in + -*)set "./$1";; + esac; + case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in + ???[sx]*):;;*)false;;esac;fi + '\'' sh + ' +fi +as_executable_p=$as_test_x + +# 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 + +# 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 ntfs-3g $as_me 2010.5.16, which was +generated by GNU Autoconf 2.61. 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 + +cat >>$CONFIG_STATUS <<_ACEOF +# 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_cs_usage="\ +\`$as_me' instantiates files from templates according to the +current configuration. + +Usage: $0 [OPTIONS] [FILE]... + + -h, --help print this help, then exit + -V, --version print version number and configuration settings, then exit + -q, --quiet 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_cs_version="\\ +ntfs-3g config.status 2010.5.16 +configured by $0, generated by GNU Autoconf 2.61, + with options \\"`echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\" + +Copyright (C) 2006 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' +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +# If no file are specified by the user, then we need to provide default +# value. By we need to know if files were specified by the user. +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=$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 ) + echo "$ac_cs_version"; exit ;; + --debug | --debu | --deb | --de | --d | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + CONFIG_FILES="$CONFIG_FILES $ac_optarg" + ac_need_defaults=false;; + --header | --heade | --head | --hea ) + $ac_shift + CONFIG_HEADERS="$CONFIG_HEADERS $ac_optarg" + ac_need_defaults=false;; + --he | --h) + # Conflict between --help and --header + { echo "$as_me: error: ambiguous option: $1 +Try \`$0 --help' for more information." >&2 + { (exit 1); exit 1; }; };; + --help | --hel | -h ) + 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. + -*) { echo "$as_me: error: unrecognized option: $1 +Try \`$0 --help' for more information." >&2 + { (exit 1); exit 1; }; } ;; + + *) ac_config_targets="$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 +if \$ac_cs_recheck; then + echo "running CONFIG_SHELL=$SHELL $SHELL $0 "$ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6 + CONFIG_SHELL=$SHELL + export CONFIG_SHELL + exec $SHELL "$0"$ac_configure_args \$ac_configure_extra_args --no-create --no-recursion +fi + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX + echo "$ac_log" +} >&5 + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF +# +# INIT-COMMANDS +# +AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF + +# Handling of arguments. +for ac_config_target in $ac_config_targets +do + case $ac_config_target in + "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; + "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; + "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; + "include/Makefile") CONFIG_FILES="$CONFIG_FILES include/Makefile" ;; + "include/fuse-lite/Makefile") CONFIG_FILES="$CONFIG_FILES include/fuse-lite/Makefile" ;; + "include/ntfs-3g/Makefile") CONFIG_FILES="$CONFIG_FILES include/ntfs-3g/Makefile" ;; + "libfuse-lite/Makefile") CONFIG_FILES="$CONFIG_FILES libfuse-lite/Makefile" ;; + "libntfs-3g/Makefile") CONFIG_FILES="$CONFIG_FILES libntfs-3g/Makefile" ;; + "libntfs-3g/libntfs-3g.pc") CONFIG_FILES="$CONFIG_FILES libntfs-3g/libntfs-3g.pc" ;; + "libntfs-3g/libntfs-3g.script.so") CONFIG_FILES="$CONFIG_FILES libntfs-3g/libntfs-3g.script.so" ;; + "src/Makefile") CONFIG_FILES="$CONFIG_FILES src/Makefile" ;; + "src/ntfs-3g.8") CONFIG_FILES="$CONFIG_FILES src/ntfs-3g.8" ;; + "src/ntfs-3g.probe.8") CONFIG_FILES="$CONFIG_FILES src/ntfs-3g.probe.8" ;; + "src/ntfs-3g.usermap.8") CONFIG_FILES="$CONFIG_FILES src/ntfs-3g.usermap.8" ;; + "src/ntfs-3g.secaudit.8") CONFIG_FILES="$CONFIG_FILES src/ntfs-3g.secaudit.8" ;; + + *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5 +echo "$as_me: error: invalid argument: $ac_config_target" >&2;} + { (exit 1); exit 1; }; };; + 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= + trap 'exit_status=$? + { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status +' 0 + trap '{ (exit 1); exit 1; }' 1 2 13 15 +} +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && + test -n "$tmp" && test -d "$tmp" +} || +{ + tmp=./conf$$-$RANDOM + (umask 077 && mkdir "$tmp") +} || +{ + echo "$me: cannot create a temporary directory in ." >&2 + { (exit 1); exit 1; } +} + +# +# Set up the sed scripts for CONFIG_FILES section. +# + +# No need to generate the scripts if there are no CONFIG_FILES. +# This happens for instance when ./config.status config.h +if test -n "$CONFIG_FILES"; then + +_ACEOF + + + +ac_delim='%!_!# ' +for ac_last_try in false false false false false :; do + cat >conf$$subs.sed <<_ACEOF +SHELL!$SHELL$ac_delim +PATH_SEPARATOR!$PATH_SEPARATOR$ac_delim +PACKAGE_NAME!$PACKAGE_NAME$ac_delim +PACKAGE_TARNAME!$PACKAGE_TARNAME$ac_delim +PACKAGE_VERSION!$PACKAGE_VERSION$ac_delim +PACKAGE_STRING!$PACKAGE_STRING$ac_delim +PACKAGE_BUGREPORT!$PACKAGE_BUGREPORT$ac_delim +exec_prefix!$exec_prefix$ac_delim +prefix!$prefix$ac_delim +program_transform_name!$program_transform_name$ac_delim +bindir!$bindir$ac_delim +sbindir!$sbindir$ac_delim +libexecdir!$libexecdir$ac_delim +datarootdir!$datarootdir$ac_delim +datadir!$datadir$ac_delim +sysconfdir!$sysconfdir$ac_delim +sharedstatedir!$sharedstatedir$ac_delim +localstatedir!$localstatedir$ac_delim +includedir!$includedir$ac_delim +oldincludedir!$oldincludedir$ac_delim +docdir!$docdir$ac_delim +infodir!$infodir$ac_delim +htmldir!$htmldir$ac_delim +dvidir!$dvidir$ac_delim +pdfdir!$pdfdir$ac_delim +psdir!$psdir$ac_delim +libdir!$libdir$ac_delim +localedir!$localedir$ac_delim +mandir!$mandir$ac_delim +DEFS!$DEFS$ac_delim +ECHO_C!$ECHO_C$ac_delim +ECHO_N!$ECHO_N$ac_delim +ECHO_T!$ECHO_T$ac_delim +LIBS!$LIBS$ac_delim +build_alias!$build_alias$ac_delim +host_alias!$host_alias$ac_delim +target_alias!$target_alias$ac_delim +build!$build$ac_delim +build_cpu!$build_cpu$ac_delim +build_vendor!$build_vendor$ac_delim +build_os!$build_os$ac_delim +host!$host$ac_delim +host_cpu!$host_cpu$ac_delim +host_vendor!$host_vendor$ac_delim +host_os!$host_os$ac_delim +target!$target$ac_delim +target_cpu!$target_cpu$ac_delim +target_vendor!$target_vendor$ac_delim +target_os!$target_os$ac_delim +INSTALL_PROGRAM!$INSTALL_PROGRAM$ac_delim +INSTALL_SCRIPT!$INSTALL_SCRIPT$ac_delim +INSTALL_DATA!$INSTALL_DATA$ac_delim +am__isrc!$am__isrc$ac_delim +CYGPATH_W!$CYGPATH_W$ac_delim +PACKAGE!$PACKAGE$ac_delim +VERSION!$VERSION$ac_delim +ACLOCAL!$ACLOCAL$ac_delim +AUTOCONF!$AUTOCONF$ac_delim +AUTOMAKE!$AUTOMAKE$ac_delim +AUTOHEADER!$AUTOHEADER$ac_delim +MAKEINFO!$MAKEINFO$ac_delim +install_sh!$install_sh$ac_delim +STRIP!$STRIP$ac_delim +INSTALL_STRIP_PROGRAM!$INSTALL_STRIP_PROGRAM$ac_delim +mkdir_p!$mkdir_p$ac_delim +AWK!$AWK$ac_delim +SET_MAKE!$SET_MAKE$ac_delim +am__leading_dot!$am__leading_dot$ac_delim +AMTAR!$AMTAR$ac_delim +am__tar!$am__tar$ac_delim +am__untar!$am__untar$ac_delim +MAINTAINER_MODE_TRUE!$MAINTAINER_MODE_TRUE$ac_delim +MAINTAINER_MODE_FALSE!$MAINTAINER_MODE_FALSE$ac_delim +MAINT!$MAINT$ac_delim +CC!$CC$ac_delim +CFLAGS!$CFLAGS$ac_delim +LDFLAGS!$LDFLAGS$ac_delim +CPPFLAGS!$CPPFLAGS$ac_delim +ac_ct_CC!$ac_ct_CC$ac_delim +EXEEXT!$EXEEXT$ac_delim +OBJEXT!$OBJEXT$ac_delim +DEPDIR!$DEPDIR$ac_delim +am__include!$am__include$ac_delim +am__quote!$am__quote$ac_delim +AMDEP_TRUE!$AMDEP_TRUE$ac_delim +AMDEP_FALSE!$AMDEP_FALSE$ac_delim +AMDEPBACKSLASH!$AMDEPBACKSLASH$ac_delim +CCDEPMODE!$CCDEPMODE$ac_delim +am__fastdepCC_TRUE!$am__fastdepCC_TRUE$ac_delim +am__fastdepCC_FALSE!$am__fastdepCC_FALSE$ac_delim +LN_S!$LN_S$ac_delim +SED!$SED$ac_delim +GREP!$GREP$ac_delim +EGREP!$EGREP$ac_delim +ECHO!$ECHO$ac_delim +AR!$AR$ac_delim +RANLIB!$RANLIB$ac_delim +_ACEOF + + if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 97; then + break + elif $ac_last_try; then + { { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5 +echo "$as_me: error: could not make $CONFIG_STATUS" >&2;} + { (exit 1); exit 1; }; } + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done + +ac_eof=`sed -n '/^CEOF[0-9]*$/s/CEOF/0/p' conf$$subs.sed` +if test -n "$ac_eof"; then + ac_eof=`echo "$ac_eof" | sort -nru | sed 1q` + ac_eof=`expr $ac_eof + 1` +fi + +cat >>$CONFIG_STATUS <<_ACEOF +cat >"\$tmp/subs-1.sed" <<\CEOF$ac_eof +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +_ACEOF +sed ' +s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g +s/^/s,@/; s/!/@,|#_!!_#|/ +:n +t n +s/'"$ac_delim"'$/,g/; t +s/$/\\/; p +N; s/^.*\n//; s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g; b n +' >>$CONFIG_STATUS >$CONFIG_STATUS <<_ACEOF +CEOF$ac_eof +_ACEOF + + +ac_delim='%!_!# ' +for ac_last_try in false false false false false :; do + cat >conf$$subs.sed <<_ACEOF +DSYMUTIL!$DSYMUTIL$ac_delim +NMEDIT!$NMEDIT$ac_delim +CPP!$CPP$ac_delim +CXX!$CXX$ac_delim +CXXFLAGS!$CXXFLAGS$ac_delim +ac_ct_CXX!$ac_ct_CXX$ac_delim +CXXDEPMODE!$CXXDEPMODE$ac_delim +am__fastdepCXX_TRUE!$am__fastdepCXX_TRUE$ac_delim +am__fastdepCXX_FALSE!$am__fastdepCXX_FALSE$ac_delim +CXXCPP!$CXXCPP$ac_delim +F77!$F77$ac_delim +FFLAGS!$FFLAGS$ac_delim +ac_ct_F77!$ac_ct_F77$ac_delim +LIBTOOL!$LIBTOOL$ac_delim +MV!$MV$ac_delim +RM!$RM$ac_delim +LDCONFIG!$LDCONFIG$ac_delim +PKG_CONFIG!$PKG_CONFIG$ac_delim +FUSE_MODULE_CFLAGS!$FUSE_MODULE_CFLAGS$ac_delim +FUSE_MODULE_LIBS!$FUSE_MODULE_LIBS$ac_delim +LIBOBJS!$LIBOBJS$ac_delim +pkgconfigdir!$pkgconfigdir$ac_delim +ntfs3gincludedir!$ntfs3gincludedir$ac_delim +rootbindir!$rootbindir$ac_delim +rootsbindir!$rootsbindir$ac_delim +rootlibdir!$rootlibdir$ac_delim +LIBNTFS_3G_VERSION!$LIBNTFS_3G_VERSION$ac_delim +LIBFUSE_LITE_LIBS!$LIBFUSE_LITE_LIBS$ac_delim +OUTPUT_FORMAT!$OUTPUT_FORMAT$ac_delim +FUSE_INTERNAL_TRUE!$FUSE_INTERNAL_TRUE$ac_delim +FUSE_INTERNAL_FALSE!$FUSE_INTERNAL_FALSE$ac_delim +GENERATE_LDSCRIPT_TRUE!$GENERATE_LDSCRIPT_TRUE$ac_delim +GENERATE_LDSCRIPT_FALSE!$GENERATE_LDSCRIPT_FALSE$ac_delim +WINDOWS_TRUE!$WINDOWS_TRUE$ac_delim +WINDOWS_FALSE!$WINDOWS_FALSE$ac_delim +NTFS_DEVICE_DEFAULT_IO_OPS_TRUE!$NTFS_DEVICE_DEFAULT_IO_OPS_TRUE$ac_delim +NTFS_DEVICE_DEFAULT_IO_OPS_FALSE!$NTFS_DEVICE_DEFAULT_IO_OPS_FALSE$ac_delim +RUN_LDCONFIG_TRUE!$RUN_LDCONFIG_TRUE$ac_delim +RUN_LDCONFIG_FALSE!$RUN_LDCONFIG_FALSE$ac_delim +REALLYSTATIC_TRUE!$REALLYSTATIC_TRUE$ac_delim +REALLYSTATIC_FALSE!$REALLYSTATIC_FALSE$ac_delim +INSTALL_LIBRARY_TRUE!$INSTALL_LIBRARY_TRUE$ac_delim +INSTALL_LIBRARY_FALSE!$INSTALL_LIBRARY_FALSE$ac_delim +ENABLE_MOUNT_HELPER_TRUE!$ENABLE_MOUNT_HELPER_TRUE$ac_delim +ENABLE_MOUNT_HELPER_FALSE!$ENABLE_MOUNT_HELPER_FALSE$ac_delim +MKDIR_P!$MKDIR_P$ac_delim +LTLIBOBJS!$LTLIBOBJS$ac_delim +_ACEOF + + if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 47; then + break + elif $ac_last_try; then + { { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5 +echo "$as_me: error: could not make $CONFIG_STATUS" >&2;} + { (exit 1); exit 1; }; } + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done + +ac_eof=`sed -n '/^CEOF[0-9]*$/s/CEOF/0/p' conf$$subs.sed` +if test -n "$ac_eof"; then + ac_eof=`echo "$ac_eof" | sort -nru | sed 1q` + ac_eof=`expr $ac_eof + 1` +fi + +cat >>$CONFIG_STATUS <<_ACEOF +cat >"\$tmp/subs-2.sed" <<\CEOF$ac_eof +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b end +_ACEOF +sed ' +s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g +s/^/s,@/; s/!/@,|#_!!_#|/ +:n +t n +s/'"$ac_delim"'$/,g/; t +s/$/\\/; p +N; s/^.*\n//; s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g; b n +' >>$CONFIG_STATUS >$CONFIG_STATUS <<_ACEOF +:end +s/|#_!!_#|//g +CEOF$ac_eof +_ACEOF + + +# VPATH may cause trouble with some makes, so we remove $(srcdir), +# ${srcdir} and @srcdir@ 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[ ]*=/{ +s/:*\$(srcdir):*/:/ +s/:*\${srcdir}:*/:/ +s/:*@srcdir@:*/:/ +s/^\([^=]*=[ ]*\):*/\1/ +s/:*$// +s/^[^=]*=[ ]*$// +}' +fi + +cat >>$CONFIG_STATUS <<\_ACEOF +fi # test -n "$CONFIG_FILES" + + +for ac_tag in :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS +do + case $ac_tag in + :[FHLC]) ac_mode=$ac_tag; continue;; + esac + case $ac_mode$ac_tag in + :[FHL]*:*);; + :L* | :C*:*) { { echo "$as_me:$LINENO: error: Invalid tag $ac_tag." >&5 +echo "$as_me: error: Invalid tag $ac_tag." >&2;} + { (exit 1); exit 1; }; };; + :[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="$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 || + { { echo "$as_me:$LINENO: error: cannot find input file: $ac_f" >&5 +echo "$as_me: error: cannot find input file: $ac_f" >&2;} + { (exit 1); exit 1; }; };; + esac + ac_file_inputs="$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 "`IFS=: + echo $* | sed 's|^[^:]*/||;s|:[^:]*/|, |g'`" by configure." + if test x"$ac_file" != x-; then + configure_input="$ac_file. $configure_input" + { echo "$as_me:$LINENO: creating $ac_file" >&5 +echo "$as_me: creating $ac_file" >&6;} + fi + + case $ac_tag in + *:-:* | *:-) cat >"$tmp/stdin";; + 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 || +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" + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || { $as_mkdir_p && mkdir -p "$as_dir"; } || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`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 || +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" || { { echo "$as_me:$LINENO: error: cannot create directory $as_dir" >&5 +echo "$as_me: error: cannot create directory $as_dir" >&2;} + { (exit 1); exit 1; }; }; } + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`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 +# 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= + +case `sed -n '/datarootdir/ { + p + q +} +/@datadir@/p +/@docdir@/p +/@infodir@/p +/@localedir@/p +/@mandir@/p +' $ac_file_inputs` in +*datarootdir*) ac_datarootdir_seen=yes;; +*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) + { echo "$as_me:$LINENO: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF + 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 + sed "$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s&@configure_input@&$configure_input&;t t +s&@top_builddir@&$ac_top_builddir_sub&;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 +" $ac_file_inputs | sed -f "$tmp/subs-1.sed" | sed -f "$tmp/subs-2.sed" >$tmp/out + +test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && + { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } && + { echo "$as_me:$LINENO: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined." >&5 +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 "$tmp/stdin" + case $ac_file in + -) cat "$tmp/out"; rm -f "$tmp/out";; + *) rm -f "$ac_file"; mv "$tmp/out" $ac_file;; + esac + ;; + :H) + # + # CONFIG_HEADER + # +_ACEOF + +# Transform confdefs.h into a sed script `conftest.defines', that +# substitutes the proper values into config.h.in to produce config.h. +rm -f conftest.defines conftest.tail +# First, append a space to every undef/define line, to ease matching. +echo 's/$/ /' >conftest.defines +# Then, protect against being on the right side of a sed subst, or in +# an unquoted here document, in config.status. If some macros were +# called several times there might be several #defines for the same +# symbol, which is useless. But do not sort them, since the last +# AC_DEFINE must be honored. +ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* +# These sed commands are passed to sed as "A NAME B PARAMS C VALUE D", where +# NAME is the cpp macro being defined, VALUE is the value it is being given. +# PARAMS is the parameter list in the macro definition--in most cases, it's +# just an empty string. +ac_dA='s,^\\([ #]*\\)[^ ]*\\([ ]*' +ac_dB='\\)[ (].*,\\1define\\2' +ac_dC=' ' +ac_dD=' ,' + +uniq confdefs.h | + sed -n ' + t rset + :rset + s/^[ ]*#[ ]*define[ ][ ]*// + t ok + d + :ok + s/[\\&,]/\\&/g + s/^\('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/ '"$ac_dA"'\1'"$ac_dB"'\2'"${ac_dC}"'\3'"$ac_dD"'/p + s/^\('"$ac_word_re"'\)[ ]*\(.*\)/'"$ac_dA"'\1'"$ac_dB$ac_dC"'\2'"$ac_dD"'/p + ' >>conftest.defines + +# Remove the space that was appended to ease matching. +# Then 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. +# (The regexp can be short, since the line contains either #define or #undef.) +echo 's/ $// +s,^[ #]*u.*,/* & */,' >>conftest.defines + +# Break up conftest.defines: +ac_max_sed_lines=50 + +# First sed command is: sed -f defines.sed $ac_file_inputs >"$tmp/out1" +# Second one is: sed -f defines.sed "$tmp/out1" >"$tmp/out2" +# Third one will be: sed -f defines.sed "$tmp/out2" >"$tmp/out1" +# et cetera. +ac_in='$ac_file_inputs' +ac_out='"$tmp/out1"' +ac_nxt='"$tmp/out2"' + +while : +do + # Write a here document: + cat >>$CONFIG_STATUS <<_ACEOF + # First, check the format of the line: + cat >"\$tmp/defines.sed" <<\\CEOF +/^[ ]*#[ ]*undef[ ][ ]*$ac_word_re[ ]*\$/b def +/^[ ]*#[ ]*define[ ][ ]*$ac_word_re[( ]/b def +b +:def +_ACEOF + sed ${ac_max_sed_lines}q conftest.defines >>$CONFIG_STATUS + echo 'CEOF + sed -f "$tmp/defines.sed"' "$ac_in >$ac_out" >>$CONFIG_STATUS + ac_in=$ac_out; ac_out=$ac_nxt; ac_nxt=$ac_in + sed 1,${ac_max_sed_lines}d conftest.defines >conftest.tail + grep . conftest.tail >/dev/null || break + rm -f conftest.defines + mv conftest.tail conftest.defines +done +rm -f conftest.defines conftest.tail + +echo "ac_result=$ac_in" >>$CONFIG_STATUS +cat >>$CONFIG_STATUS <<\_ACEOF + if test x"$ac_file" != x-; then + echo "/* $configure_input */" >"$tmp/config.h" + cat "$ac_result" >>"$tmp/config.h" + if diff $ac_file "$tmp/config.h" >/dev/null 2>&1; then + { echo "$as_me:$LINENO: $ac_file is unchanged" >&5 +echo "$as_me: $ac_file is unchanged" >&6;} + else + rm -f $ac_file + mv "$tmp/config.h" $ac_file + fi + else + echo "/* $configure_input */" + cat "$ac_result" + fi + rm -f "$tmp/out12" +# 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 || +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) { echo "$as_me:$LINENO: executing $ac_file commands" >&5 +echo "$as_me: executing $ac_file commands" >&6;} + ;; + esac + + + case $ac_file$ac_mode in + "depfiles":C) test x"$AMDEP_TRUE" != x"" || for mf in $CONFIG_FILES; do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named `Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # Grep'ing the whole file is not good either: AIX grep has a line + # limit of 2048, but all sed's we know have understand at least 4000. + if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then + dirpart=`$as_dirname -- "$mf" || +$as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$mf" : 'X\(//\)[^/]' \| \ + X"$mf" : 'X\(//\)$' \| \ + X"$mf" : 'X\(/\)' \| . 2>/dev/null || +echo X"$mf" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + else + continue + fi + # Extract the definition of DEPDIR, am__include, and am__quote + # from the Makefile without running `make'. + DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` + test -z "$DEPDIR" && continue + am__include=`sed -n 's/^am__include = //p' < "$mf"` + test -z "am__include" && continue + am__quote=`sed -n 's/^am__quote = //p' < "$mf"` + # When using ansi2knr, U may be empty or an underscore; expand it + U=`sed -n 's/^U = //p' < "$mf"` + # Find all dependency output files, they are included files with + # $(DEPDIR) in their names. We invoke sed twice because it is the + # simplest approach to changing $(DEPDIR) to its actual value in the + # expansion. + for file in `sed -n " + s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`$as_dirname -- "$file" || +$as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$file" : 'X\(//\)[^/]' \| \ + X"$file" : 'X\(//\)$' \| \ + X"$file" : 'X\(/\)' \| . 2>/dev/null || +echo X"$file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + { as_dir=$dirpart/$fdir + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || { $as_mkdir_p && mkdir -p "$as_dir"; } || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`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 || +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" || { { echo "$as_me:$LINENO: error: cannot create directory $as_dir" >&5 +echo "$as_me: error: cannot create directory $as_dir" >&2;} + { (exit 1); exit 1; }; }; } + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done +done + ;; + + esac +done # for ac_tag + + +{ (exit 0); exit 0; } +_ACEOF +chmod +x $CONFIG_STATUS +ac_clean_files=$ac_clean_files_save + + +# 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 || { (exit 1); exit 1; } +fi + + +if test "${with_fuse}" = "external"; then + if ! echo "x$FUSE_LIB_PATH" | grep -- "x-L/lib" > /dev/null; then + cat <@])], + , + [ + case "${target_os}" in + linux*) enable_mount_helper="yes" ;; + *) enable_mount_helper="no" ;; + esac + ] +) + +AC_ARG_ENABLE( + [ldscript], + [AS_HELP_STRING([--enable-ldscript],[use ldscript instead of .so symlink])], + , + [enable_ldscript="no"] +) + +AC_ARG_ENABLE( + [ldconfig], + [AS_HELP_STRING([--disable-ldconfig],[do not update dynamic linker cache using ldconfig])], + , + [enable_ldconfig="yes"] +) + +AC_ARG_ENABLE( + [library], + [AS_HELP_STRING([--disable-library],[do not install libntfs-3g but link it into ntfs-3g])], + , + [enable_library="yes"] +) + +AC_ARG_ENABLE( + [mtab], + [AS_HELP_STRING([--disable-mtab],[disable and ignore usage of /etc/mtab])], + , + [enable_mtab="yes"] +) + +AC_ARG_ENABLE( + [posix-acls], + [AS_HELP_STRING([--enable-posix-acls],[enable POSIX ACL support])], + , + [enable_posix_acls="no"] +) + +AC_ARG_ENABLE( + [device-default-io-ops], + [AS_HELP_STRING([--disable-device-default-io-ops],[install default IO ops])], + , + [enable_device_default_io_ops="yes"] +) + +AC_ARG_ENABLE( + [nfconv], + [AS_HELP_STRING([--disable-nfconv],[disable the 'nfconv' patch, which adds support for Unicode normalization form conversion when built on Mac OS X @<:@default=enabled for Mac OS X@:>@])], + [enable_nfconv="no"], + [ + case "${target_os}" in + darwin*) enable_nfconv="yes" ;; + *) enable_nfconv="no" ;; + esac + ] +) + +# pthread_rwlock_t requires _GNU_SOURCE +AC_GNU_SOURCE + +# Programs +AC_PROG_CC(gcc cc) +AC_PROG_LN_S +AM_PROG_CC_C_O + +ifdef( + [LT_INIT], + [LT_INIT], + [AC_PROG_LIBTOOL] +) + +AC_PATH_PROG([MV], [mv]) +AC_PATH_PROG([RM], [rm]) +AC_PATH_PROG([SED], [sed]) +AC_ARG_VAR([LDCONFIG], [ldconfig utility]) +AC_PATH_PROG([LDCONFIG], [ldconfig], [true], [/sbin /usr/sbin $PATH]) + +# Environment +AC_MSG_CHECKING([Windows OS]) +case "${target}" in +*-mingw32*|*-winnt*|*-cygwin*) + AC_MSG_RESULT([yes]) + WINDOWS="yes" + AC_DEFINE( + [WINDOWS], + [1], + [Define to 1 if this is a Windows OS] + ) + ;; +*) + AC_MSG_RESULT([no]) + WINDOWS="no" + ;; +esac + +AC_MSG_CHECKING([fuse compatibility]) +case "${target_os}" in +linux*) + AC_ARG_WITH( + [fuse], + [AS_HELP_STRING([--with-fuse=],[Select FUSE library: internal or external @<:@default=internal@:>@])], + , + [with_fuse="internal"] + ) + ;; +darwin*|netbsd*|solaris*) + with_fuse="external" + ;; +freebsd*) + AC_MSG_ERROR([Please see FreeBSD support at http://www.freshports.org/sysutils/fusefs-ntfs]) + ;; +*) + AC_MSG_ERROR([ntfs-3g can be built for Linux, FreeBSD, Mac OS X, NetBSD, and Solaris only.]) + ;; +esac +AC_MSG_RESULT([${with_fuse}]) + +case "${target_os}" in +solaris*) + if test "x$GCC" != "xyes" ; then + AC_MSG_ERROR([ntfs-3g can be built only with gcc on Solaris. Install it by 'pkg install gcc-dev' and retry.)]) + fi + ;; +esac + +if test "${enable_ldscript}" = "yes"; then + AC_MSG_CHECKING([Output format]) + OUTPUT_FORMAT="$(${CC} ${CFLAGS} ${LDFLAGS} -Wl,--verbose 2>&1 | ${SED} -n 's/^OUTPUT_FORMAT("\([[^"]]*\)",.*/\1/p')" + if test -z "${OUTPUT_FORMAT}"; then + AC_MSG_RESULT([None]) + else + AC_MSG_RESULT([${OUTPUT_FORMAT}]) + OUTPUT_FORMAT="OUTPUT_FORMAT ( ${OUTPUT_FORMAT} )" + fi +fi + +# Libraries +if test "${with_fuse}" = "internal"; then + AC_CHECK_LIB( + [pthread], + [pthread_create], + [LIBFUSE_LITE_LIBS="${LIBFUSE_LITE_LIBS} -lpthread"], + [AC_MSG_ERROR([Cannot find pthread library])] + ) + AC_DEFINE( + [_REENTRANT], + [1], + [Required define if using POSIX threads] + ) + # required so that we re-compile anything + AC_DEFINE( + [FUSE_INTERNAL], + [1], + [Define to 1 if using internal fuse] + ) +else + if test -z "$PKG_CONFIG"; then + AC_PATH_PROG(PKG_CONFIG, pkg-config, no) + fi + test "x${PKG_CONFIG}" = "xno" && AC_MSG_ERROR([pkg-config wasn't found! Please install from your vendor, or see http://pkg-config.freedesktop.org/wiki/]) + # Libraries often install their metadata .pc files in directories + # not searched by pkg-config. Let's workaround this. + export PKG_CONFIG_PATH=${PKG_CONFIG_PATH}:/lib/pkgconfig:/usr/lib/pkgconfig:/opt/gnome/lib/pkgconfig:/usr/share/pkgconfig:/usr/local/lib/pkgconfig:$prefix/lib/pkgconfig:/opt/gnome/share/pkgconfig:/usr/local/share/pkgconfig + PKG_CHECK_MODULES( + [FUSE_MODULE], + [fuse >= 2.6.0], + , + [ + AC_MSG_ERROR([FUSE >= 2.6.0 was not found. Either older FUSE is still present, or FUSE is not fully installed (e.g. fuse, libfuse, libfuse2, libfuse-dev, etc packages). Source code: http://fuse.sf.net]) + ] + ) + FUSE_LIB_PATH=`$PKG_CONFIG --libs-only-L fuse | sed -e 's,/[/]*,/,g' -e 's,[ ]*$,,'` +fi + +# Checks for header files. +AC_HEADER_STDC +AC_CHECK_HEADERS([ctype.h fcntl.h libgen.h libintl.h limits.h locale.h \ + mntent.h stddef.h stdint.h stdlib.h stdio.h stdarg.h string.h \ + strings.h errno.h time.h unistd.h utime.h wchar.h getopt.h features.h \ + endian.h byteswap.h sys/byteorder.h sys/endian.h sys/param.h \ + sys/ioctl.h sys/mkdev.h sys/mount.h sys/stat.h sys/types.h sys/vfs.h \ + sys/statvfs.h sys/sysmacros.h linux/major.h linux/fd.h linux/hdreg.h \ + machine/endian.h windows.h syslog.h]) + +# Checks for typedefs, structures, and compiler characteristics. +AC_HEADER_STDBOOL +AC_C_BIGENDIAN( + , + [ + AC_DEFINE( + [WORDS_LITTLEENDIAN], + [1], + [Define to 1 if your processor stores words with the least significant + byte first (like Intel and VAX, unlike Motorola and SPARC).] + ) + ] + , +) +AC_C_INLINE +AC_TYPE_OFF_T +AC_TYPE_SIZE_T +AC_STRUCT_ST_BLOCKS +AC_CHECK_MEMBERS([struct stat.st_rdev]) +AC_CHECK_MEMBERS([struct stat.st_atim]) +AC_CHECK_MEMBERS([struct stat.st_atimespec]) +AC_CHECK_MEMBERS([struct stat.st_atimensec]) + +# For the 'nfconv' patch (Mac OS X only): +case "${target_os}" in +darwin*) + if test "${enable_nfconv}" = "yes"; then + AC_CHECK_HEADER( + [CoreFoundation/CoreFoundation.h], + [ + LDFLAGS="${LDFLAGS} -framework CoreFoundation" + AC_DEFINE( + [ENABLE_NFCONV], + [1], + [Define to 1 if the nfconv patch should be enabled] + ) + ], + AC_MSG_ERROR([[Cannot find CoreFoundation required for 'nfconv' functionality Mac OS X. You may use the --disable-nfconv 'configure' option to avoid this error.]]) + ) + fi + ;; +esac + +# Checks for library functions. +AC_FUNC_GETMNTENT +AC_FUNC_MBRTOWC +AC_FUNC_MEMCMP +AC_FUNC_STAT +AC_FUNC_STRFTIME +AC_FUNC_UTIME_NULL +AC_FUNC_VPRINTF +AC_CHECK_FUNCS([ \ + atexit basename daemon dup2 fdatasync ffs getopt_long hasmntopt \ + mbsinit memmove memset realpath regcomp setlocale setxattr \ + strcasecmp strchr strdup strerror strnlen strsep strtol strtoul \ + sysconf utime utimensat gettimeofday clock_gettime fork \ +]) +AC_SYS_LARGEFILE + +if test "$GCC" = "yes" ; then + # We add -Wall to enable some compiler warnings. + CFLAGS="${CFLAGS} -Wall" +fi + +if test "${enable_pedantic}" = "yes"; then + enable_warnings="yes" + CFLAGS="${CFLAGS} -pedantic" +fi + +if test "${enable_warnings}" = "yes"; then + CFLAGS="${CFLAGS} -W -Wall -Waggregate-return -Wbad-function-cast -Wcast-align -Wcast-qual -Wdisabled-optimization -Wdiv-by-zero -Wfloat-equal -Winline -Wmissing-declarations -Wmissing-format-attribute -Wmissing-noreturn -Wmissing-prototypes -Wmultichar -Wnested-externs -Wpointer-arith -Wredundant-decls -Wshadow -Wsign-compare -Wstrict-prototypes -Wundef -Wwrite-strings -Wformat -Wformat-security -Wuninitialized" +fi + +if test "${enable_debug}" = "yes"; then + CFLAGS="${CFLAGS} -ggdb3 -DDEBUG" + AC_DEFINE( + [ENABLE_DEBUG], + [1], + [Define to 1 if debug should be enabled] + ) +fi + +test "${enable_device_default_io_ops}" = "no" && AC_DEFINE( + [NO_NTFS_DEVICE_DEFAULT_IO_OPS], + [1], + [Don't use default IO ops] +) + +test "${enable_mtab}" = "no" && AC_DEFINE([IGNORE_MTAB], [1], [Don't update /etc/mtab]) +test "${enable_posix_acls}" != "no" && AC_DEFINE([POSIXACLS], [1], [POSIX ACL support]) + +test "${enable_really_static}" = "yes" && enable_library="no" +test "${enable_library}" = "no" && enable_ldconfig="no" + +if test "x${DISTCHECK_HACK}" != "x"; then + enable_mount_helper="no" + enable_ldconfig="no" +fi + +# Settings +pkgconfigdir="\$(libdir)/pkgconfig" +ntfs3gincludedir="\$(includedir)/ntfs-3g" +# Executables should be installed to the root filesystem, otherwise +# automounting NTFS volumes can fail during boot if the driver binaries +# and their dependencies are on an unmounted partition. Use --exec-prefix +# to override this. +if test "x${exec_prefix}" = "xNONE"; then + rootbindir="/bin" + rootsbindir="/sbin" + rootlibdir="/lib${libdir##*/lib}" +else + rootbindir="\$(bindir)" + rootsbindir="\$(sbindir)" + rootlibdir="\$(libdir)" +fi +AC_SUBST([pkgconfigdir]) +AC_SUBST([ntfs3gincludedir]) +AC_SUBST([rootbindir]) +AC_SUBST([rootsbindir]) +AC_SUBST([rootlibdir]) +AC_SUBST([LIBNTFS_3G_VERSION]) +AC_SUBST([LIBFUSE_LITE_LIBS]) +AC_SUBST([OUTPUT_FORMAT]) +AM_CONDITIONAL([FUSE_INTERNAL], [test "${with_fuse}" = "internal"]) +AM_CONDITIONAL([GENERATE_LDSCRIPT], [test "${enable_ldscript}" = "yes"]) +AM_CONDITIONAL([WINDOWS], [test "${WINDOWS}" = "yes"]) +AM_CONDITIONAL([NTFS_DEVICE_DEFAULT_IO_OPS], [test "${enable_device_default_io_ops}" = "yes"]) +AM_CONDITIONAL([RUN_LDCONFIG], [test "${enable_ldconfig}" = "yes"]) +AM_CONDITIONAL([REALLYSTATIC], [test "${enable_really_static}" = "yes"]) +AM_CONDITIONAL([INSTALL_LIBRARY], [test "${enable_library}" = "yes"]) +AM_CONDITIONAL([ENABLE_MOUNT_HELPER], [test "${enable_mount_helper}" = "yes"]) + +# workaround for /dev/null; then + cat <. + +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 outputing dependencies. + libtool Whether libtool is used (yes/no). + +Report bugs to . +EOF + exit $? + ;; + -v | --v*) + echo "depcomp $scriptversion" + exit $? + ;; +esac + +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" + +# 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 + +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 -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + mv "$tmpdepfile" "$depfile" + ;; + +gcc) +## 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). +## - 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 -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + echo "$object : \\" > "$depfile" + alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz +## 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. + tr ' ' ' +' < "$tmpdepfile" | +## 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. +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -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 -eq 0; then : + else + 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 ' ' ' +' < "$tmpdepfile" \ + | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \ + tr ' +' ' ' >> $depfile + echo >> $depfile + + # The second pass generates a dummy entry for each header file. + tr ' ' ' +' < "$tmpdepfile" \ + | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ + >> $depfile + else + # The sourcefile does not contain any dependencies, so just + # store a dummy comment line, to avoid errors with the Makefile + # "include basename.Plo" scheme. + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +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. + dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` + test "x$dir" = "x$object" && dir= + base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` + 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 -eq 0; then : + else + rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" + exit $stat + fi + + for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" + do + test -f "$tmpdepfile" && break + done + if test -f "$tmpdepfile"; then + # Each line is of the form `foo.o: dependent.h'. + # Do two passes, one to just change these to + # `$object: dependent.h' and one to simply `dependent.h:'. + sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" + # That's a tab and a space in the []. + sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile" + else + # The sourcefile does not contain any dependencies, so just + # store a dummy comment line, to avoid errors with the Makefile + # "include basename.Plo" scheme. + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +icc) + # Intel's C compiler understands `-MD -MF file'. However on + # icc -MD -MF foo.d -c -o sub/foo.o sub/foo.c + # ICC 7.0 will fill foo.d with something like + # foo.o: sub/foo.c + # foo.o: sub/foo.h + # which is wrong. We want: + # sub/foo.o: sub/foo.c + # sub/foo.o: sub/foo.h + # sub/foo.c: + # sub/foo.h: + # ICC 7.1 will output + # foo.o: sub/foo.c sub/foo.h + # and will wrap long lines using \ : + # foo.o: sub/foo.c ... \ + # sub/foo.h ... \ + # ... + + "$@" -MD -MF "$tmpdepfile" + stat=$? + if test $stat -eq 0; then : + else + 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. + dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` + test "x$dir" = "x$object" && dir= + base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` + 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 -eq 0; then : + else + 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,^.*\.[a-z]*:,$object:," "$tmpdepfile" > "$depfile" + # Add `dependent.h:' lines. + sed -ne '2,${; s/^ *//; s/ \\*$//; s/$/:/; p;}' "$tmpdepfile" >> "$depfile" + else + echo "#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. + dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` + test "x$dir" = "x$object" && dir= + base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` + + if test "$libtool" = yes; then + # With Tru64 cc, shared objects can also be used to make a + # static library. This mechanism is used in libtool 1.4 series to + # handle both shared and static libraries in a single compilation. + # With libtool 1.4, dependencies were output in $dir.libs/$base.lo.d. + # + # With libtool 1.5 this exception was removed, and libtool now + # 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.libs/$base.lo.d # libtool 1.4 + tmpdepfile2=$dir$base.o.d # libtool 1.5 + tmpdepfile3=$dir.libs/$base.o.d # libtool 1.5 + tmpdepfile4=$dir.libs/$base.d # Compaq CCC V6.2-504 + "$@" -Wc,-MD + else + tmpdepfile1=$dir$base.o.d + tmpdepfile2=$dir$base.d + tmpdepfile3=$dir$base.d + tmpdepfile4=$dir$base.d + "$@" -MD + fi + + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" + exit $stat + fi + + for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" + do + test -f "$tmpdepfile" && break + done + if test -f "$tmpdepfile"; then + sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" + # That's a tab and a space in the []. + sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile" + else + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +#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 $1 != '--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:^[ ]*[^: ][^:][^:]*\:[ ]*:'"$object"'\: :' > "$tmpdepfile" + rm -f "$depfile" + cat < "$tmpdepfile" > "$depfile" + tr ' ' ' +' < "$tmpdepfile" | \ +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + 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 $1 != '--mode=compile'; do + shift + done + shift + fi + # X makedepend + shift + cleared=no + for arg in "$@"; do + case $cleared in + no) + set ""; shift + cleared=yes ;; + esac + 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. + -*|$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" + cat < "$tmpdepfile" > "$depfile" + sed '1,2d' "$tmpdepfile" | tr ' ' ' +' | \ +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + 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 $1 != '--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, regardless of -o, + # because we must use -o when running libtool. + "$@" || exit $? + IFS=" " + for arg + do + case "$arg" in + "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") + set fnord "$@" + shift + shift + ;; + *) + set fnord "$@" "$arg" + shift + shift + ;; + esac + done + "$@" -E | + sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::echo "`cygpath -u \\"\1\\"`":p' | sort | uniq > "$tmpdepfile" + rm -f "$depfile" + echo "$object : \\" > "$depfile" + . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s:: \1 \\:p' >> "$depfile" + echo " " >> "$depfile" + . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s::\1\::p' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +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-end: "$" +# End: diff --git a/include/Makefile.am b/include/Makefile.am new file mode 100755 index 0000000..0fa1702 --- a/dev/null +++ b/include/Makefile.am @@ -0,0 +1,4 @@ + +MAINTAINERCLEANFILES = $(srcdir)/Makefile.in + +SUBDIRS = ntfs-3g fuse-lite diff --git a/include/Makefile.in b/include/Makefile.in new file mode 100755 index 0000000..afadcc5 --- a/dev/null +++ b/include/Makefile.in @@ -0,0 +1,503 @@ +# Makefile.in generated by automake 1.10.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008 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@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@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 = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +subdir = include +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +SOURCES = +DIST_SOURCES = +RECURSIVE_TARGETS = all-recursive check-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 uninstall-recursive +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = $(SUBDIRS) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DSYMUTIL = @DSYMUTIL@ +ECHO = @ECHO@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +F77 = @F77@ +FFLAGS = @FFLAGS@ +FUSE_MODULE_CFLAGS = @FUSE_MODULE_CFLAGS@ +FUSE_MODULE_LIBS = @FUSE_MODULE_LIBS@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDCONFIG = @LDCONFIG@ +LDFLAGS = @LDFLAGS@ +LIBFUSE_LITE_LIBS = @LIBFUSE_LITE_LIBS@ +LIBNTFS_3G_VERSION = @LIBNTFS_3G_VERSION@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MV = @MV@ +NMEDIT = @NMEDIT@ +OBJEXT = @OBJEXT@ +OUTPUT_FORMAT = @OUTPUT_FORMAT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PKG_CONFIG = @PKG_CONFIG@ +RANLIB = @RANLIB@ +RM = @RM@ +SED = @SED@ +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_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_F77 = @ac_ct_F77@ +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 = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +ntfs3gincludedir = @ntfs3gincludedir@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgconfigdir = @pkgconfigdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +rootbindir = @rootbindir@ +rootlibdir = @rootlibdir@ +rootsbindir = @rootsbindir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +MAINTAINERCLEANFILES = $(srcdir)/Makefile.in +SUBDIRS = ntfs-3g fuse-lite +all: all-recursive + +.SUFFIXES: +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu include/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu include/Makefile +.PRECIOUS: 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__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +# 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. +$(RECURSIVE_TARGETS): + @failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; 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; \ + (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" + +$(RECURSIVE_CLEAN_TARGETS): + @failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + 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 || \ + tags="$$tags $$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(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 $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$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 \ + test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + distdir=`$(am__cd) $(distdir) && pwd`; \ + top_distdir=`$(am__cd) $(top_distdir) && pwd`; \ + (cd $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$top_distdir" \ + distdir="$$distdir/$$subdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + distdir) \ + || exit 1; \ + fi; \ + done +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: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) +clean: clean-recursive + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-recursive + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +info: info-recursive + +info-am: + +install-data-am: + +install-dvi: install-dvi-recursive + +install-exec-am: + +install-html: install-html-recursive + +install-info: install-info-recursive + +install-man: + +install-pdf: install-pdf-recursive + +install-ps: install-ps-recursive + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: + +.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) install-am \ + install-strip + +.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ + all all-am check check-am clean clean-generic clean-libtool \ + ctags ctags-recursive distclean distclean-generic \ + distclean-libtool 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-strip installcheck \ + installcheck-am installdirs installdirs-am maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am tags tags-recursive \ + uninstall uninstall-am + +# 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: diff --git a/include/fuse-lite/Makefile.am b/include/fuse-lite/Makefile.am new file mode 100755 index 0000000..15a84bb --- a/dev/null +++ b/include/fuse-lite/Makefile.am @@ -0,0 +1,10 @@ + +MAINTAINERCLEANFILES = Makefile.in + +noinst_HEADERS = \ + fuse.h \ + fuse_common.h \ + fuse_lowlevel.h \ + fuse_lowlevel_compat.h \ + fuse_opt.h \ + fuse_kernel.h diff --git a/include/fuse-lite/Makefile.in b/include/fuse-lite/Makefile.in new file mode 100755 index 0000000..e9fece0 --- a/dev/null +++ b/include/fuse-lite/Makefile.in @@ -0,0 +1,400 @@ +# Makefile.in generated by automake 1.10.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008 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@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@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 = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +subdir = include/fuse-lite +DIST_COMMON = $(noinst_HEADERS) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +SOURCES = +DIST_SOURCES = +HEADERS = $(noinst_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DSYMUTIL = @DSYMUTIL@ +ECHO = @ECHO@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +F77 = @F77@ +FFLAGS = @FFLAGS@ +FUSE_MODULE_CFLAGS = @FUSE_MODULE_CFLAGS@ +FUSE_MODULE_LIBS = @FUSE_MODULE_LIBS@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDCONFIG = @LDCONFIG@ +LDFLAGS = @LDFLAGS@ +LIBFUSE_LITE_LIBS = @LIBFUSE_LITE_LIBS@ +LIBNTFS_3G_VERSION = @LIBNTFS_3G_VERSION@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MV = @MV@ +NMEDIT = @NMEDIT@ +OBJEXT = @OBJEXT@ +OUTPUT_FORMAT = @OUTPUT_FORMAT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PKG_CONFIG = @PKG_CONFIG@ +RANLIB = @RANLIB@ +RM = @RM@ +SED = @SED@ +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_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_F77 = @ac_ct_F77@ +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 = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +ntfs3gincludedir = @ntfs3gincludedir@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgconfigdir = @pkgconfigdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +rootbindir = @rootbindir@ +rootlibdir = @rootlibdir@ +rootsbindir = @rootsbindir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +MAINTAINERCLEANFILES = Makefile.in +noinst_HEADERS = \ + fuse.h \ + fuse_common.h \ + fuse_lowlevel.h \ + fuse_lowlevel_compat.h \ + fuse_opt.h \ + fuse_kernel.h + +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu include/fuse-lite/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu include/fuse-lite/Makefile +.PRECIOUS: 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__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(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 $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$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 $(HEADERS) +installdirs: +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: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) +clean: clean-am + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +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 + +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 mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool ctags distclean distclean-generic \ + distclean-libtool 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-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am tags uninstall \ + uninstall-am + +# 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: diff --git a/include/fuse-lite/fuse.h b/include/fuse-lite/fuse.h new file mode 100755 index 0000000..1b3291a --- a/dev/null +++ b/include/fuse-lite/fuse.h @@ -0,0 +1,654 @@ +/* + FUSE: Filesystem in Userspace + Copyright (C) 2001-2007 Miklos Szeredi + + This program can be distributed under the terms of the GNU LGPLv2. + See the file COPYING.LIB. +*/ + +#ifndef _FUSE_H_ +#define _FUSE_H_ + +/** @file + * + * This file defines the library interface of FUSE + */ + +#include "fuse_common.h" + +#include +#include +#include +#ifdef HAVE_SYS_TYPES_H +#include +#endif + +#include + +#if HAVE_SYS_STATVFS_H +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* ----------------------------------------------------------- * + * Basic FUSE API * + * ----------------------------------------------------------- */ + +/** Handle for a FUSE filesystem */ +struct fuse; + +/** Structure containing a raw command */ +struct fuse_cmd; + +/** Function to add an entry in a readdir() operation + * + * @param buf the buffer passed to the readdir() operation + * @param name the file name of the directory entry + * @param stat file attributes, can be NULL + * @param off offset of the next entry or zero + * @return 1 if buffer is full, zero otherwise + */ +typedef int (*fuse_fill_dir_t) (void *buf, const char *name, + const struct stat *stbuf, off_t off); + +/** + * The file system operations: + * + * Most of these should work very similarly to the well known UNIX + * file system operations. A major exception is that instead of + * returning an error in 'errno', the operation should return the + * negated error value (-errno) directly. + * + * All methods are optional, but some are essential for a useful + * filesystem (e.g. getattr). Open, flush, release, fsync, opendir, + * releasedir, fsyncdir, access, create, ftruncate, fgetattr, lock, + * init and destroy are special purpose methods, without which a full + * featured filesystem can still be implemented. + * + * Almost all operations take a path which can be of any length. + * + * Changed in fuse 2.8.0 (regardless of API version) + * Previously, paths were limited to a length of PATH_MAX. + */ + +struct fuse_operations { + /** Get file attributes. + * + * Similar to stat(). The 'st_dev' and 'st_blksize' fields are + * ignored. The 'st_ino' field is ignored except if the 'use_ino' + * mount option is given. + */ + int (*getattr) (const char *, struct stat *); + + /** Read the target of a symbolic link + * + * The buffer should be filled with a null terminated string. The + * buffer size argument includes the space for the terminating + * null character. If the linkname is too long to fit in the + * buffer, it should be truncated. The return value should be 0 + * for success. + */ + int (*readlink) (const char *, char *, size_t); + + /** Create a file node + * + * This is called for creation of all non-directory, non-symlink + * nodes. If the filesystem defines a create() method, then for + * regular files that will be called instead. + */ + int (*mknod) (const char *, mode_t, dev_t); + + /** Create a directory + * + * Note that the mode argument may not have the type specification + * bits set, i.e. S_ISDIR(mode) can be false. To obtain the + * correct directory type bits use mode|S_IFDIR + * */ + int (*mkdir) (const char *, mode_t); + + /** Remove a file */ + int (*unlink) (const char *); + + /** Remove a directory */ + int (*rmdir) (const char *); + + /** Create a symbolic link */ + int (*symlink) (const char *, const char *); + + /** Rename a file */ + int (*rename) (const char *, const char *); + + /** Create a hard link to a file */ + int (*link) (const char *, const char *); + + /** Change the permission bits of a file */ + int (*chmod) (const char *, mode_t); + + /** Change the owner and group of a file */ + int (*chown) (const char *, uid_t, gid_t); + + /** Change the size of a file */ + int (*truncate) (const char *, off_t); + + /** Change the access and/or modification times of a file + * + * Deprecated, use utimens() instead. + */ + int (*utime) (const char *, struct utimbuf *); + + /** File open operation + * + * No creation (O_CREAT, O_EXCL) and by default also no + * truncation (O_TRUNC) flags will be passed to open(). If an + * application specifies O_TRUNC, fuse first calls truncate() + * and then open(). Only if 'atomic_o_trunc' has been + * specified and kernel version is 2.6.24 or later, O_TRUNC is + * passed on to open. + * + * Unless the 'default_permissions' mount option is given, + * open should check if the operation is permitted for the + * given flags. Optionally open may also return an arbitrary + * filehandle in the fuse_file_info structure, which will be + * passed to all file operations. + * + * Changed in version 2.2 + */ + int (*open) (const char *, struct fuse_file_info *); + + /** Read data from an open file + * + * Read should return exactly the number of bytes requested except + * on EOF or error, otherwise the rest of the data will be + * substituted with zeroes. An exception to this is when the + * 'direct_io' mount option is specified, in which case the return + * value of the read system call will reflect the return value of + * this operation. + * + * Changed in version 2.2 + */ + int (*read) (const char *, char *, size_t, off_t, + struct fuse_file_info *); + + /** Write data to an open file + * + * Write should return exactly the number of bytes requested + * except on error. An exception to this is when the 'direct_io' + * mount option is specified (see read operation). + * + * Changed in version 2.2 + */ + int (*write) (const char *, const char *, size_t, off_t, + struct fuse_file_info *); + + /** Get file system statistics + * + * The 'f_frsize', 'f_favail', 'f_fsid' and 'f_flag' fields are ignored + * + * Replaced 'struct statfs' parameter with 'struct statvfs' in + * version 2.5 + */ +#if HAVE_SYS_STATVFS_H + + int (*statfs) (const char *, struct statvfs *); + +#endif + /** Possibly flush cached data + * + * BIG NOTE: This is not equivalent to fsync(). It's not a + * request to sync dirty data. + * + * Flush is called on each close() of a file descriptor. So if a + * filesystem wants to return write errors in close() and the file + * has cached dirty data, this is a good place to write back data + * and return any errors. Since many applications ignore close() + * errors this is not always useful. + * + * NOTE: The flush() method may be called more than once for each + * open(). This happens if more than one file descriptor refers + * to an opened file due to dup(), dup2() or fork() calls. It is + * not possible to determine if a flush is final, so each flush + * should be treated equally. Multiple write-flush sequences are + * relatively rare, so this shouldn't be a problem. + * + * Filesystems shouldn't assume that flush will always be called + * after some writes, or that if will be called at all. + * + * Changed in version 2.2 + */ + int (*flush) (const char *, struct fuse_file_info *); + + /** Release an open file + * + * Release is called when there are no more references to an open + * file: all file descriptors are closed and all memory mappings + * are unmapped. + * + * For every open() call there will be exactly one release() call + * with the same flags and file descriptor. It is possible to + * have a file opened more than once, in which case only the last + * release will mean, that no more reads/writes will happen on the + * file. The return value of release is ignored. + * + * Changed in version 2.2 + */ + int (*release) (const char *, struct fuse_file_info *); + + /** Synchronize file contents + * + * If the datasync parameter is non-zero, then only the user data + * should be flushed, not the meta data. + * + * Changed in version 2.2 + */ + int (*fsync) (const char *, int, struct fuse_file_info *); + + /** Set extended attributes */ + int (*setxattr) (const char *, const char *, const char *, size_t, int); + + /** Get extended attributes */ + int (*getxattr) (const char *, const char *, char *, size_t); + + /** List extended attributes */ + int (*listxattr) (const char *, char *, size_t); + + /** Remove extended attributes */ + int (*removexattr) (const char *, const char *); + + /** Open directory + * + * This method should check if the open operation is permitted for + * this directory + * + * Introduced in version 2.3 + */ + int (*opendir) (const char *, struct fuse_file_info *); + + /** Read directory + * + * The filesystem may choose between two modes of operation: + * + * 1) The readdir implementation ignores the offset parameter, and + * passes zero to the filler function's offset. The filler + * function will not return '1' (unless an error happens), so the + * whole directory is read in a single readdir operation. + * + * 2) The readdir implementation keeps track of the offsets of the + * directory entries. It uses the offset parameter and always + * passes non-zero offset to the filler function. When the buffer + * is full (or an error happens) the filler function will return + * '1'. + * + * Introduced in version 2.3 + */ + int (*readdir) (const char *, void *, fuse_fill_dir_t, off_t, + struct fuse_file_info *); + + /** Release directory + * + * Introduced in version 2.3 + */ + int (*releasedir) (const char *, struct fuse_file_info *); + + /** Synchronize directory contents + * + * If the datasync parameter is non-zero, then only the user data + * should be flushed, not the meta data + * + * Introduced in version 2.3 + */ + int (*fsyncdir) (const char *, int, struct fuse_file_info *); + + /** + * Initialize filesystem + * + * The return value will passed in the private_data field of + * fuse_context to all file operations and as a parameter to the + * destroy() method. + * + * Introduced in version 2.3 + * Changed in version 2.6 + */ + void *(*init) (struct fuse_conn_info *conn); + + /** + * Clean up filesystem + * + * Called on filesystem exit. + * + * Introduced in version 2.3 + */ + void (*destroy) (void *); + + /** + * Check file access permissions + * + * This will be called for the access() system call. If the + * 'default_permissions' mount option is given, this method is not + * called. + * + * This method is not called under Linux kernel versions 2.4.x + * + * Introduced in version 2.5 + */ + int (*access) (const char *, int); + + /** + * Create and open a file + * + * If the file does not exist, first create it with the specified + * mode, and then open it. + * + * If this method is not implemented or under Linux kernel + * versions earlier than 2.6.15, the mknod() and open() methods + * will be called instead. + * + * Introduced in version 2.5 + */ + int (*create) (const char *, mode_t, struct fuse_file_info *); + + /** + * Change the size of an open file + * + * This method is called instead of the truncate() method if the + * truncation was invoked from an ftruncate() system call. + * + * If this method is not implemented or under Linux kernel + * versions earlier than 2.6.15, the truncate() method will be + * called instead. + * + * Introduced in version 2.5 + */ + int (*ftruncate) (const char *, off_t, struct fuse_file_info *); + + /** + * Get attributes from an open file + * + * This method is called instead of the getattr() method if the + * file information is available. + * + * Currently this is only called after the create() method if that + * is implemented (see above). Later it may be called for + * invocations of fstat() too. + * + * Introduced in version 2.5 + */ + int (*fgetattr) (const char *, struct stat *, struct fuse_file_info *); + + /** + * Perform POSIX file locking operation + * + * The cmd argument will be either F_GETLK, F_SETLK or F_SETLKW. + * + * For the meaning of fields in 'struct flock' see the man page + * for fcntl(2). The l_whence field will always be set to + * SEEK_SET. + * + * For checking lock ownership, the 'fuse_file_info->owner' + * argument must be used. + * + * For F_GETLK operation, the library will first check currently + * held locks, and if a conflicting lock is found it will return + * information without calling this method. This ensures, that + * for local locks the l_pid field is correctly filled in. The + * results may not be accurate in case of race conditions and in + * the presence of hard links, but it's unlikly that an + * application would rely on accurate GETLK results in these + * cases. If a conflicting lock is not found, this method will be + * called, and the filesystem may fill out l_pid by a meaningful + * value, or it may leave this field zero. + * + * For F_SETLK and F_SETLKW the l_pid field will be set to the pid + * of the process performing the locking operation. + * + * Note: if this method is not implemented, the kernel will still + * allow file locking to work locally. Hence it is only + * interesting for network filesystems and similar. + * + * Introduced in version 2.6 + */ + int (*lock) (const char *, struct fuse_file_info *, int cmd, + struct flock *); + + /** + * Change the access and modification times of a file with + * nanosecond resolution + * + * Introduced in version 2.6 + */ + int (*utimens) (const char *, const struct timespec tv[2]); + + /** + * Map block index within file to block index within device + * + * Note: This makes sense only for block device backed filesystems + * mounted with the 'blkdev' option + * + * Introduced in version 2.6 + */ + int (*bmap) (const char *, size_t blocksize, uint64_t *idx); + unsigned int flag_nullpath_ok : 1; + + /** + * Flag indicating that the filesystem accepts special + * UTIME_NOW and UTIME_OMIT values in its utimens operation. + */ + unsigned int flag_utime_omit_ok : 1; + + /** + * Reserved flags, don't set + */ + unsigned int flag_reserved : 30; + +}; + +/** Extra context that may be needed by some filesystems + * + * The uid, gid and pid fields are not filled in case of a writepage + * operation. + */ +struct fuse_context { + /** Pointer to the fuse object */ + struct fuse *fuse; + + /** User ID of the calling process */ + uid_t uid; + + /** Group ID of the calling process */ + gid_t gid; + + /** Thread ID of the calling process */ + pid_t pid; + + /** Private filesystem data */ + void *private_data; + +#ifdef POSIXACLS + /** Umask of the calling process (introduced in version 2.8) */ + mode_t umask; +#endif +}; + +/* ----------------------------------------------------------- * + * More detailed API * + * ----------------------------------------------------------- */ + +/** + * Create a new FUSE filesystem. + * + * @param ch the communication channel + * @param args argument vector + * @param op the filesystem operations + * @param op_size the size of the fuse_operations structure + * @param user_data user data supplied in the context during the init() method + * @return the created FUSE handle + */ +struct fuse *fuse_new(struct fuse_chan *ch, struct fuse_args *args, + const struct fuse_operations *op, size_t op_size, + void *user_data); + +/** + * Destroy the FUSE handle. + * + * The communication channel attached to the handle is also destroyed. + * + * NOTE: This function does not unmount the filesystem. If this is + * needed, call fuse_unmount() before calling this function. + * + * @param f the FUSE handle + */ +void fuse_destroy(struct fuse *f); + +/** + * FUSE event loop. + * + * Requests from the kernel are processed, and the appropriate + * operations are called. + * + * @param f the FUSE handle + * @return 0 if no error occurred, -1 otherwise + */ +int fuse_loop(struct fuse *f); + +/** + * Exit from event loop + * + * @param f the FUSE handle + */ +void fuse_exit(struct fuse *f); + +/** + * Get the current context + * + * The context is only valid for the duration of a filesystem + * operation, and thus must not be stored and used later. + * + * @return the context + */ +struct fuse_context *fuse_get_context(void); + +/** + * Check if a request has already been interrupted + * + * @param req request handle + * @return 1 if the request has been interrupted, 0 otherwise + */ +int fuse_interrupted(void); + +/* + * Stacking API + */ + +/** + * Fuse filesystem object + * + * This is opaque object represents a filesystem layer + */ +struct fuse_fs; + +/* + * These functions call the relevant filesystem operation, and return + * the result. + * + * If the operation is not defined, they return -ENOSYS, with the + * exception of fuse_fs_open, fuse_fs_release, fuse_fs_opendir, + * fuse_fs_releasedir and fuse_fs_statfs, which return 0. + */ + +int fuse_fs_getattr(struct fuse_fs *fs, const char *path, struct stat *buf); +int fuse_fs_fgetattr(struct fuse_fs *fs, const char *path, struct stat *buf, + struct fuse_file_info *fi); +int fuse_fs_rename(struct fuse_fs *fs, const char *oldpath, + const char *newpath); +int fuse_fs_unlink(struct fuse_fs *fs, const char *path); +int fuse_fs_rmdir(struct fuse_fs *fs, const char *path); +int fuse_fs_symlink(struct fuse_fs *fs, const char *linkname, + const char *path); +int fuse_fs_link(struct fuse_fs *fs, const char *oldpath, const char *newpath); +int fuse_fs_release(struct fuse_fs *fs, const char *path, + struct fuse_file_info *fi); +int fuse_fs_open(struct fuse_fs *fs, const char *path, + struct fuse_file_info *fi); +int fuse_fs_read(struct fuse_fs *fs, const char *path, char *buf, size_t size, + off_t off, struct fuse_file_info *fi); +int fuse_fs_write(struct fuse_fs *fs, const char *path, const char *buf, + size_t size, off_t off, struct fuse_file_info *fi); +int fuse_fs_fsync(struct fuse_fs *fs, const char *path, int datasync, + struct fuse_file_info *fi); +int fuse_fs_flush(struct fuse_fs *fs, const char *path, + struct fuse_file_info *fi); + +#if HAVE_SYS_STATVFS_H +int fuse_fs_statfs(struct fuse_fs *fs, const char *path, struct statvfs *buf); +#endif + +int fuse_fs_opendir(struct fuse_fs *fs, const char *path, + struct fuse_file_info *fi); +int fuse_fs_readdir(struct fuse_fs *fs, const char *path, void *buf, + fuse_fill_dir_t filler, off_t off, + struct fuse_file_info *fi); +int fuse_fs_fsyncdir(struct fuse_fs *fs, const char *path, int datasync, + struct fuse_file_info *fi); +int fuse_fs_releasedir(struct fuse_fs *fs, const char *path, + struct fuse_file_info *fi); +int fuse_fs_create(struct fuse_fs *fs, const char *path, mode_t mode, + struct fuse_file_info *fi); +int fuse_fs_lock(struct fuse_fs *fs, const char *path, + struct fuse_file_info *fi, int cmd, struct flock *lock); +int fuse_fs_chmod(struct fuse_fs *fs, const char *path, mode_t mode); +int fuse_fs_chown(struct fuse_fs *fs, const char *path, uid_t uid, gid_t gid); +int fuse_fs_truncate(struct fuse_fs *fs, const char *path, off_t size); +int fuse_fs_ftruncate(struct fuse_fs *fs, const char *path, off_t size, + struct fuse_file_info *fi); +int fuse_fs_utimens(struct fuse_fs *fs, const char *path, + const struct timespec tv[2]); +int fuse_fs_access(struct fuse_fs *fs, const char *path, int mask); +int fuse_fs_readlink(struct fuse_fs *fs, const char *path, char *buf, + size_t len); +int fuse_fs_mknod(struct fuse_fs *fs, const char *path, mode_t mode, + dev_t rdev); +int fuse_fs_mkdir(struct fuse_fs *fs, const char *path, mode_t mode); +int fuse_fs_setxattr(struct fuse_fs *fs, const char *path, const char *name, + const char *value, size_t size, int flags); +int fuse_fs_getxattr(struct fuse_fs *fs, const char *path, const char *name, + char *value, size_t size); +int fuse_fs_listxattr(struct fuse_fs *fs, const char *path, char *list, + size_t size); +int fuse_fs_removexattr(struct fuse_fs *fs, const char *path, + const char *name); +int fuse_fs_bmap(struct fuse_fs *fs, const char *path, size_t blocksize, + uint64_t *idx); +void fuse_fs_init(struct fuse_fs *fs, struct fuse_conn_info *conn); +void fuse_fs_destroy(struct fuse_fs *fs); + +/** + * Create a new fuse filesystem object + * + * This is usually called from the factory of a fuse module to create + * a new instance of a filesystem. + * + * @param op the filesystem operations + * @param op_size the size of the fuse_operations structure + * @param user_data user data supplied in the context during the init() method + * @return a new filesystem object + */ +struct fuse_fs *fuse_fs_new(const struct fuse_operations *op, size_t op_size, + void *user_data); + +/* ----------------------------------------------------------- * + * Advanced API for event handling, don't worry about this... * + * ----------------------------------------------------------- */ + +/* NOTE: the following functions are deprecated, and will be removed + from the 3.0 API. Use the lowlevel session functions instead */ + +/** Get session from fuse object */ +struct fuse_session *fuse_get_session(struct fuse *f); + +#ifdef __cplusplus +} +#endif + +#endif /* _FUSE_H_ */ diff --git a/include/fuse-lite/fuse_common.h b/include/fuse-lite/fuse_common.h new file mode 100755 index 0000000..819bb8d --- a/dev/null +++ b/include/fuse-lite/fuse_common.h @@ -0,0 +1,193 @@ +/* + FUSE: Filesystem in Userspace + Copyright (C) 2001-2007 Miklos Szeredi + + This program can be distributed under the terms of the GNU LGPLv2. + See the file COPYING.LIB. +*/ + +/** @file */ + +#if !defined(_FUSE_H_) && !defined(_FUSE_LOWLEVEL_H_) +#error "Never include directly; use or instead." +#endif + +#ifndef _FUSE_COMMON_H_ +#define _FUSE_COMMON_H_ + +#include "fuse_opt.h" +#include /* temporary */ +#include + +/** Major version of FUSE library interface */ +#define FUSE_MAJOR_VERSION 2 + +/** Minor version of FUSE library interface */ +#ifdef POSIXACLS +#define FUSE_MINOR_VERSION 8 +#else +#define FUSE_MINOR_VERSION 7 +#endif + +#define FUSE_MAKE_VERSION(maj, min) ((maj) * 10 + (min)) +#define FUSE_VERSION FUSE_MAKE_VERSION(FUSE_MAJOR_VERSION, FUSE_MINOR_VERSION) + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef POSIXACLS +/* + * FUSE_CAP_DONT_MASK: don't apply umask to file mode on create operations + */ +#define FUSE_CAP_DONT_MASK (1 << 6) +#endif + +/** + * Information about open files + * + * Changed in version 2.5 + */ +struct fuse_file_info { + /** Open flags. Available in open() and release() */ + int flags; + + /** Old file handle, don't use */ + unsigned long fh_old; + + /** In case of a write operation indicates if this was caused by a + writepage */ + int writepage; + + /** Can be filled in by open, to use direct I/O on this file. + Introduced in version 2.4 */ + unsigned int direct_io : 1; + + /** Can be filled in by open, to indicate, that cached file data + need not be invalidated. Introduced in version 2.4 */ + unsigned int keep_cache : 1; + + /** Indicates a flush operation. Set in flush operation, also + maybe set in highlevel lock operation and lowlevel release + operation. Introduced in version 2.6 */ + unsigned int flush : 1; + + /** Padding. Do not use*/ + unsigned int padding : 29; + + /** File handle. May be filled in by filesystem in open(). + Available in all other file operations */ + uint64_t fh; + + /** Lock owner id. Available in locking operations and flush */ + uint64_t lock_owner; +}; + +/** + * Connection information, passed to the ->init() method + * + * Some of the elements are read-write, these can be changed to + * indicate the value requested by the filesystem. The requested + * value must usually be smaller than the indicated value. + */ +struct fuse_conn_info { + /** + * Major version of the protocol (read-only) + */ + unsigned proto_major; + + /** + * Minor version of the protocol (read-only) + */ + unsigned proto_minor; + + /** + * Is asynchronous read supported (read-write) + */ + unsigned async_read; + + /** + * Maximum size of the write buffer + */ + unsigned max_write; + + /** + * Maximum readahead + */ + unsigned max_readahead; + +#ifdef POSIXACLS + unsigned capable; + unsigned want; + /** + * For future use. + */ + unsigned reserved[25]; +#else + /** + * For future use. + */ + unsigned reserved[27]; +#endif + }; + +struct fuse_session; +struct fuse_chan; + +/** + * Create a FUSE mountpoint + * + * Returns a control file descriptor suitable for passing to + * fuse_new() + * + * @param mountpoint the mount point path + * @param args argument vector + * @return the communication channel on success, NULL on failure + */ +struct fuse_chan *fuse_mount(const char *mountpoint, struct fuse_args *args); + +/** + * Umount a FUSE mountpoint + * + * @param mountpoint the mount point path + * @param ch the communication channel + */ +void fuse_unmount(const char *mountpoint, struct fuse_chan *ch); + +/** + * Get the version of the library + * + * @return the version + */ +int fuse_version(void); + +/* ----------------------------------------------------------- * + * Signal handling * + * ----------------------------------------------------------- */ + +/** + * Exit session on HUP, TERM and INT signals and ignore PIPE signal + * + * Stores session in a global variable. May only be called once per + * process until fuse_remove_signal_handlers() is called. + * + * @param se the session to exit + * @return 0 on success, -1 on failure + */ +int fuse_set_signal_handlers(struct fuse_session *se); + +/** + * Restore default signal handlers + * + * Resets global session. After this fuse_set_signal_handlers() may + * be called again. + * + * @param se the same session as given in fuse_set_signal_handlers() + */ +void fuse_remove_signal_handlers(struct fuse_session *se); + +#ifdef __cplusplus +} +#endif + +#endif /* _FUSE_COMMON_H_ */ diff --git a/include/fuse-lite/fuse_kernel.h b/include/fuse-lite/fuse_kernel.h new file mode 100755 index 0000000..696de77 --- a/dev/null +++ b/include/fuse-lite/fuse_kernel.h @@ -0,0 +1,422 @@ +/* + This file defines the kernel interface of FUSE + Copyright (C) 2001-2007 Miklos Szeredi + + This program can be distributed under the terms of the GNU GPL. + See the file COPYING. + + This -- and only this -- header file may also be distributed under + the terms of the BSD Licence as follows: + + Copyright (C) 2001-2007 Miklos Szeredi. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + * + * 7.12 + * - add umask flag to input argument of open, mknod and mkdir +*/ + +#ifndef linux +#ifdef HAVE_SYS_TYPES_H +#include +#endif + +#define __u64 uint64_t +#define __u32 uint32_t +#define __s32 int32_t +#else +#include +#include +#endif + +/** Version number of this interface */ +#define FUSE_KERNEL_VERSION 7 + +/** Minor version number of this interface */ +#ifdef POSIXACLS +#define FUSE_KERNEL_MINOR_VERSION 12 +#define FUSE_KERNEL_MINOR_FALLBACK 8 +#else +#define FUSE_KERNEL_MINOR_VERSION 8 +#endif + +/** The node ID of the root inode */ +#define FUSE_ROOT_ID 1 + +/** The major number of the fuse character device */ +#define FUSE_MAJOR MISC_MAJOR + +/** The minor number of the fuse character device */ +#define FUSE_MINOR 229 + +/* Make sure all structures are padded to 64bit boundary, so 32bit + userspace works under 64bit kernels */ + +struct fuse_attr { + __u64 ino; + __u64 size; + __u64 blocks; + __u64 atime; + __u64 mtime; + __u64 ctime; + __u32 atimensec; + __u32 mtimensec; + __u32 ctimensec; + __u32 mode; + __u32 nlink; + __u32 uid; + __u32 gid; + __u32 rdev; +#ifdef POSIXACLS + __u64 filling; /* JPA needed for minor >= 12, but meaning unknown */ +#endif +}; + +struct fuse_kstatfs { + __u64 blocks; + __u64 bfree; + __u64 bavail; + __u64 files; + __u64 ffree; + __u32 bsize; + __u32 namelen; + __u32 frsize; + __u32 padding; + __u32 spare[6]; +}; + +struct fuse_file_lock { + __u64 start; + __u64 end; + __u32 type; + __u32 pid; /* tgid */ +}; + +/** + * Bitmasks for fuse_setattr_in.valid + */ +#define FATTR_MODE (1 << 0) +#define FATTR_UID (1 << 1) +#define FATTR_GID (1 << 2) +#define FATTR_SIZE (1 << 3) +#define FATTR_ATIME (1 << 4) +#define FATTR_MTIME (1 << 5) +#define FATTR_FH (1 << 6) + +/** + * Flags returned by the OPEN request + * + * FOPEN_DIRECT_IO: bypass page cache for this open file + * FOPEN_KEEP_CACHE: don't invalidate the data cache on open + */ +#define FOPEN_DIRECT_IO (1 << 0) +#define FOPEN_KEEP_CACHE (1 << 1) + +/** + * INIT request/reply flags + * FUSE_DONT_MASK: don't apply umask to file mode on create operations + */ +#define FUSE_ASYNC_READ (1 << 0) +#define FUSE_POSIX_LOCKS (1 << 1) +#define FUSE_DONT_MASK (1 << 6) +#define FUSE_BIG_WRITES (1 << 5) + +/** + * Release flags + */ +#define FUSE_RELEASE_FLUSH (1 << 0) + +enum fuse_opcode { + FUSE_LOOKUP = 1, + FUSE_FORGET = 2, /* no reply */ + FUSE_GETATTR = 3, + FUSE_SETATTR = 4, + FUSE_READLINK = 5, + FUSE_SYMLINK = 6, + FUSE_MKNOD = 8, + FUSE_MKDIR = 9, + FUSE_UNLINK = 10, + FUSE_RMDIR = 11, + FUSE_RENAME = 12, + FUSE_LINK = 13, + FUSE_OPEN = 14, + FUSE_READ = 15, + FUSE_WRITE = 16, + FUSE_STATFS = 17, + FUSE_RELEASE = 18, + FUSE_FSYNC = 20, + FUSE_SETXATTR = 21, + FUSE_GETXATTR = 22, + FUSE_LISTXATTR = 23, + FUSE_REMOVEXATTR = 24, + FUSE_FLUSH = 25, + FUSE_INIT = 26, + FUSE_OPENDIR = 27, + FUSE_READDIR = 28, + FUSE_RELEASEDIR = 29, + FUSE_FSYNCDIR = 30, + FUSE_GETLK = 31, + FUSE_SETLK = 32, + FUSE_SETLKW = 33, + FUSE_ACCESS = 34, + FUSE_CREATE = 35, + FUSE_INTERRUPT = 36, + FUSE_BMAP = 37, + FUSE_DESTROY = 38, +}; + +/* The read buffer is required to be at least 8k, but may be much larger */ +#define FUSE_MIN_READ_BUFFER 8192 +#define FUSE_COMPAT_ENTRY_OUT_SIZE 120 /* JPA */ + +struct fuse_entry_out { + __u64 nodeid; /* Inode ID */ + __u64 generation; /* Inode generation: nodeid:gen must + be unique for the fs's lifetime */ + __u64 entry_valid; /* Cache timeout for the name */ + __u64 attr_valid; /* Cache timeout for the attributes */ + __u32 entry_valid_nsec; + __u32 attr_valid_nsec; + struct fuse_attr attr; +}; + +struct fuse_forget_in { + __u64 nlookup; +}; + +#define FUSE_COMPAT_FUSE_ATTR_OUT_SIZE 96 /* JPA */ + +struct fuse_attr_out { + __u64 attr_valid; /* Cache timeout for the attributes */ + __u32 attr_valid_nsec; + __u32 dummy; + struct fuse_attr attr; +}; + +#define FUSE_COMPAT_MKNOD_IN_SIZE 8 + +struct fuse_mknod_in { + __u32 mode; + __u32 rdev; +#ifdef POSIXACLS + __u32 umask; + __u32 padding; +#endif +}; + +struct fuse_mkdir_in { + __u32 mode; + __u32 umask; +}; + +struct fuse_rename_in { + __u64 newdir; +}; + +struct fuse_link_in { + __u64 oldnodeid; +}; + +struct fuse_setattr_in { + __u32 valid; + __u32 padding; + __u64 fh; + __u64 size; + __u64 unused1; + __u64 atime; + __u64 mtime; + __u64 unused2; + __u32 atimensec; + __u32 mtimensec; + __u32 unused3; + __u32 mode; + __u32 unused4; + __u32 uid; + __u32 gid; + __u32 unused5; +}; + +struct fuse_open_in { + __u32 flags; +#ifdef POSIXACLS + __u32 unused; +#else + __u32 mode; +#endif +}; + +struct fuse_create_in { + __u32 flags; + __u32 mode; +#ifdef POSIXACLS + __u32 umask; + __u32 padding; +#endif +}; + +struct fuse_open_out { + __u64 fh; + __u32 open_flags; + __u32 padding; +}; + +struct fuse_release_in { + __u64 fh; + __u32 flags; + __u32 release_flags; + __u64 lock_owner; +}; + +struct fuse_flush_in { + __u64 fh; + __u32 unused; + __u32 padding; + __u64 lock_owner; +}; + +struct fuse_read_in { + __u64 fh; + __u64 offset; + __u32 size; + __u32 padding; +}; + +#define FUSE_COMPAT_WRITE_IN_SIZE 24 /* JPA */ + +struct fuse_write_in { + __u64 fh; + __u64 offset; + __u32 size; + __u32 write_flags; +#ifdef POSIXACLS + __u64 lock_owner; /* JPA */ + __u32 flags; /* JPA */ + __u32 padding; /* JPA */ +#endif +}; + +struct fuse_write_out { + __u32 size; + __u32 padding; +}; + +#define FUSE_COMPAT_STATFS_SIZE 48 + +struct fuse_statfs_out { + struct fuse_kstatfs st; +}; + +struct fuse_fsync_in { + __u64 fh; + __u32 fsync_flags; + __u32 padding; +}; + +struct fuse_setxattr_in { + __u32 size; + __u32 flags; +}; + +struct fuse_getxattr_in { + __u32 size; + __u32 padding; +}; + +struct fuse_getxattr_out { + __u32 size; + __u32 padding; +}; + +struct fuse_lk_in { + __u64 fh; + __u64 owner; + struct fuse_file_lock lk; +}; + +struct fuse_lk_out { + struct fuse_file_lock lk; +}; + +struct fuse_access_in { + __u32 mask; + __u32 padding; +}; + +struct fuse_init_in { + __u32 major; + __u32 minor; + __u32 max_readahead; + __u32 flags; +}; + +struct fuse_init_out { + __u32 major; + __u32 minor; + __u32 max_readahead; + __u32 flags; + __u32 unused; + __u32 max_write; +}; + +struct fuse_interrupt_in { + __u64 unique; +}; + +struct fuse_bmap_in { + __u64 block; + __u32 blocksize; + __u32 padding; +}; + +struct fuse_bmap_out { + __u64 block; +}; + +struct fuse_in_header { + __u32 len; + __u32 opcode; + __u64 unique; + __u64 nodeid; + __u32 uid; + __u32 gid; + __u32 pid; + __u32 padding; +}; + +struct fuse_out_header { + __u32 len; + __s32 error; + __u64 unique; +}; + +struct fuse_dirent { + __u64 ino; + __u64 off; + __u32 namelen; + __u32 type; + char name[0]; +}; + +#define FUSE_NAME_OFFSET offsetof(struct fuse_dirent, name) +#define FUSE_DIRENT_ALIGN(x) (((x) + sizeof(__u64) - 1) & ~(sizeof(__u64) - 1)) +#define FUSE_DIRENT_SIZE(d) \ + FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + (d)->namelen) diff --git a/include/fuse-lite/fuse_lowlevel.h b/include/fuse-lite/fuse_lowlevel.h new file mode 100755 index 0000000..5b6dc6d --- a/dev/null +++ b/include/fuse-lite/fuse_lowlevel.h @@ -0,0 +1,1375 @@ +/* + FUSE: Filesystem in Userspace + Copyright (C) 2001-2007 Miklos Szeredi + + This program can be distributed under the terms of the GNU LGPLv2. + See the file COPYING.LIB. +*/ + +#ifndef _FUSE_LOWLEVEL_H_ +#define _FUSE_LOWLEVEL_H_ + +/** @file + * + * Low level API + */ + +#include "fuse_common.h" + +#include +#include +#ifdef HAVE_SYS_TYPES_H +#include +#endif + +#include + +#if HAVE_SYS_STATVFS_H + +#include +#endif + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* ----------------------------------------------------------- * + * Miscellaneous definitions * + * ----------------------------------------------------------- */ + +/** The node ID of the root inode */ +#define FUSE_ROOT_ID 1 + +/** Inode number type */ +typedef unsigned long fuse_ino_t; + +/** Request pointer type */ +typedef struct fuse_req *fuse_req_t; + +/** + * Session + * + * This provides hooks for processing requests, and exiting + */ +struct fuse_session; + +/** + * Channel + * + * A communication channel, providing hooks for sending and receiving + * messages + */ +struct fuse_chan; + +/** Directory entry parameters supplied to fuse_reply_entry() */ +struct fuse_entry_param { + /** Unique inode number + * + * In lookup, zero means negative entry (from version 2.5) + * Returning ENOENT also means negative entry, but by setting zero + * ino the kernel may cache negative entries for entry_timeout + * seconds. + */ + fuse_ino_t ino; + + /** Generation number for this entry. + * + * The ino/generation pair should be unique for the filesystem's + * lifetime. It must be non-zero, otherwise FUSE will treat it as an + * error. + */ + unsigned long generation; + + /** Inode attributes. + * + * Even if attr_timeout == 0, attr must be correct. For example, + * for open(), FUSE uses attr.st_size from lookup() to determine + * how many bytes to request. If this value is not correct, + * incorrect data will be returned. + */ + struct stat attr; + + /** Validity timeout (in seconds) for the attributes */ + double attr_timeout; + + /** Validity timeout (in seconds) for the name */ + double entry_timeout; +}; + +/** Additional context associated with requests */ +struct fuse_ctx { + /** User ID of the calling process */ + uid_t uid; + + /** Group ID of the calling process */ + gid_t gid; + + /** Thread ID of the calling process */ + pid_t pid; + +#ifdef POSIXACLS + /** Umask of the calling process (introduced in version 2.8) */ + mode_t umask; +#endif +}; + +/* 'to_set' flags in setattr */ +#define FUSE_SET_ATTR_MODE (1 << 0) +#define FUSE_SET_ATTR_UID (1 << 1) +#define FUSE_SET_ATTR_GID (1 << 2) +#define FUSE_SET_ATTR_SIZE (1 << 3) +#define FUSE_SET_ATTR_ATIME (1 << 4) +#define FUSE_SET_ATTR_MTIME (1 << 5) +#define FUSE_SET_ATTR_ATIME_NOW (1 << 7) +#define FUSE_SET_ATTR_MTIME_NOW (1 << 8) + +/* ----------------------------------------------------------- * + * Request methods and replies * + * ----------------------------------------------------------- */ + +/** + * Low level filesystem operations + * + * Most of the methods (with the exception of init and destroy) + * receive a request handle (fuse_req_t) as their first argument. + * This handle must be passed to one of the specified reply functions. + * + * This may be done inside the method invocation, or after the call + * has returned. The request handle is valid until one of the reply + * functions is called. + * + * Other pointer arguments (name, fuse_file_info, etc) are not valid + * after the call has returned, so if they are needed later, their + * contents have to be copied. + * + * The filesystem sometimes needs to handle a return value of -ENOENT + * from the reply function, which means, that the request was + * interrupted, and the reply discarded. For example if + * fuse_reply_open() return -ENOENT means, that the release method for + * this file will not be called. + */ +struct fuse_lowlevel_ops { + /** + * Initialize filesystem + * + * Called before any other filesystem method + * + * There's no reply to this function + * + * @param userdata the user data passed to fuse_lowlevel_new() + */ + void (*init) (void *userdata, struct fuse_conn_info *conn); + + /** + * Clean up filesystem + * + * Called on filesystem exit + * + * There's no reply to this function + * + * @param userdata the user data passed to fuse_lowlevel_new() + */ + void (*destroy) (void *userdata); + + /** + * Look up a directory entry by name and get its attributes. + * + * Valid replies: + * fuse_reply_entry + * fuse_reply_err + * + * @param req request handle + * @param parent inode number of the parent directory + * @param name the name to look up + */ + void (*lookup) (fuse_req_t req, fuse_ino_t parent, const char *name); + + /** + * Forget about an inode + * + * The nlookup parameter indicates the number of lookups + * previously performed on this inode. + * + * If the filesystem implements inode lifetimes, it is recommended + * that inodes acquire a single reference on each lookup, and lose + * nlookup references on each forget. + * + * The filesystem may ignore forget calls, if the inodes don't + * need to have a limited lifetime. + * + * On unmount it is not guaranteed, that all referenced inodes + * will receive a forget message. + * + * Valid replies: + * fuse_reply_none + * + * @param req request handle + * @param ino the inode number + * @param nlookup the number of lookups to forget + */ + void (*forget) (fuse_req_t req, fuse_ino_t ino, unsigned long nlookup); + + /** + * Get file attributes + * + * Valid replies: + * fuse_reply_attr + * fuse_reply_err + * + * @param req request handle + * @param ino the inode number + * @param fi for future use, currently always NULL + */ + void (*getattr) (fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *fi); + + /** + * Set file attributes + * + * In the 'attr' argument only members indicated by the 'to_set' + * bitmask contain valid values. Other members contain undefined + * values. + * + * If the setattr was invoked from the ftruncate() system call + * under Linux kernel versions 2.6.15 or later, the fi->fh will + * contain the value set by the open method or will be undefined + * if the open method didn't set any value. Otherwise (not + * ftruncate call, or kernel version earlier than 2.6.15) the fi + * parameter will be NULL. + * + * Valid replies: + * fuse_reply_attr + * fuse_reply_err + * + * @param req request handle + * @param ino the inode number + * @param attr the attributes + * @param to_set bit mask of attributes which should be set + * @param fi file information, or NULL + * + * Changed in version 2.5: + * file information filled in for ftruncate + */ + void (*setattr) (fuse_req_t req, fuse_ino_t ino, struct stat *attr, + int to_set, struct fuse_file_info *fi); + + /** + * Read symbolic link + * + * Valid replies: + * fuse_reply_readlink + * fuse_reply_err + * + * @param req request handle + * @param ino the inode number + */ + void (*readlink) (fuse_req_t req, fuse_ino_t ino); + + /** + * Create file node + * + * Create a regular file, character device, block device, fifo or + * socket node. + * + * Valid replies: + * fuse_reply_entry + * fuse_reply_err + * + * @param req request handle + * @param parent inode number of the parent directory + * @param name to create + * @param mode file type and mode with which to create the new file + * @param rdev the device number (only valid if created file is a device) + */ + void (*mknod) (fuse_req_t req, fuse_ino_t parent, const char *name, + mode_t mode, dev_t rdev); + + /** + * Create a directory + * + * Valid replies: + * fuse_reply_entry + * fuse_reply_err + * + * @param req request handle + * @param parent inode number of the parent directory + * @param name to create + * @param mode with which to create the new file + */ + void (*mkdir) (fuse_req_t req, fuse_ino_t parent, const char *name, + mode_t mode); + + /** + * Remove a file + * + * Valid replies: + * fuse_reply_err + * + * @param req request handle + * @param parent inode number of the parent directory + * @param name to remove + */ + void (*unlink) (fuse_req_t req, fuse_ino_t parent, const char *name); + + /** + * Remove a directory + * + * Valid replies: + * fuse_reply_err + * + * @param req request handle + * @param parent inode number of the parent directory + * @param name to remove + */ + void (*rmdir) (fuse_req_t req, fuse_ino_t parent, const char *name); + + /** + * Create a symbolic link + * + * Valid replies: + * fuse_reply_entry + * fuse_reply_err + * + * @param req request handle + * @param link the contents of the symbolic link + * @param parent inode number of the parent directory + * @param name to create + */ + void (*symlink) (fuse_req_t req, const char *link, fuse_ino_t parent, + const char *name); + + /** Rename a file + * + * Valid replies: + * fuse_reply_err + * + * @param req request handle + * @param parent inode number of the old parent directory + * @param name old name + * @param newparent inode number of the new parent directory + * @param newname new name + */ + void (*rename) (fuse_req_t req, fuse_ino_t parent, const char *name, + fuse_ino_t newparent, const char *newname); + + /** + * Create a hard link + * + * Valid replies: + * fuse_reply_entry + * fuse_reply_err + * + * @param req request handle + * @param ino the old inode number + * @param newparent inode number of the new parent directory + * @param newname new name to create + */ + void (*link) (fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent, + const char *newname); + + /** + * Open a file + * + * Open flags (with the exception of O_CREAT, O_EXCL, O_NOCTTY and + * O_TRUNC) are available in fi->flags. + * + * Filesystem may store an arbitrary file handle (pointer, index, + * etc) in fi->fh, and use this in other all other file operations + * (read, write, flush, release, fsync). + * + * Filesystem may also implement stateless file I/O and not store + * anything in fi->fh. + * + * There are also some flags (direct_io, keep_cache) which the + * filesystem may set in fi, to change the way the file is opened. + * See fuse_file_info structure in for more details. + * + * Valid replies: + * fuse_reply_open + * fuse_reply_err + * + * @param req request handle + * @param ino the inode number + * @param fi file information + */ + void (*open) (fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *fi); + + /** + * Read data + * + * Read should send exactly the number of bytes requested except + * on EOF or error, otherwise the rest of the data will be + * substituted with zeroes. An exception to this is when the file + * has been opened in 'direct_io' mode, in which case the return + * value of the read system call will reflect the return value of + * this operation. + * + * fi->fh will contain the value set by the open method, or will + * be undefined if the open method didn't set any value. + * + * Valid replies: + * fuse_reply_buf + * fuse_reply_err + * + * @param req request handle + * @param ino the inode number + * @param size number of bytes to read + * @param off offset to read from + * @param fi file information + */ + void (*read) (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, + struct fuse_file_info *fi); + + /** + * Write data + * + * Write should return exactly the number of bytes requested + * except on error. An exception to this is when the file has + * been opened in 'direct_io' mode, in which case the return value + * of the write system call will reflect the return value of this + * operation. + * + * fi->fh will contain the value set by the open method, or will + * be undefined if the open method didn't set any value. + * + * Valid replies: + * fuse_reply_write + * fuse_reply_err + * + * @param req request handle + * @param ino the inode number + * @param buf data to write + * @param size number of bytes to write + * @param off offset to write to + * @param fi file information + */ + void (*write) (fuse_req_t req, fuse_ino_t ino, const char *buf, + size_t size, off_t off, struct fuse_file_info *fi); + + /** + * Flush method + * + * This is called on each close() of the opened file. + * + * Since file descriptors can be duplicated (dup, dup2, fork), for + * one open call there may be many flush calls. + * + * Filesystems shouldn't assume that flush will always be called + * after some writes, or that if will be called at all. + * + * fi->fh will contain the value set by the open method, or will + * be undefined if the open method didn't set any value. + * + * NOTE: the name of the method is misleading, since (unlike + * fsync) the filesystem is not forced to flush pending writes. + * One reason to flush data, is if the filesystem wants to return + * write errors. + * + * If the filesystem supports file locking operations (setlk, + * getlk) it should remove all locks belonging to 'fi->owner'. + * + * Valid replies: + * fuse_reply_err + * + * @param req request handle + * @param ino the inode number + * @param fi file information + */ + void (*flush) (fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *fi); + + /** + * Release an open file + * + * Release is called when there are no more references to an open + * file: all file descriptors are closed and all memory mappings + * are unmapped. + * + * For every open call there will be exactly one release call. + * + * The filesystem may reply with an error, but error values are + * not returned to close() or munmap() which triggered the + * release. + * + * fi->fh will contain the value set by the open method, or will + * be undefined if the open method didn't set any value. + * fi->flags will contain the same flags as for open. + * + * Valid replies: + * fuse_reply_err + * + * @param req request handle + * @param ino the inode number + * @param fi file information + */ + void (*release) (fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *fi); + + /** + * Synchronize file contents + * + * If the datasync parameter is non-zero, then only the user data + * should be flushed, not the meta data. + * + * Valid replies: + * fuse_reply_err + * + * @param req request handle + * @param ino the inode number + * @param datasync flag indicating if only data should be flushed + * @param fi file information + */ + void (*fsync) (fuse_req_t req, fuse_ino_t ino, int datasync, + struct fuse_file_info *fi); + + /** + * Open a directory + * + * Filesystem may store an arbitrary file handle (pointer, index, + * etc) in fi->fh, and use this in other all other directory + * stream operations (readdir, releasedir, fsyncdir). + * + * Filesystem may also implement stateless directory I/O and not + * store anything in fi->fh, though that makes it impossible to + * implement standard conforming directory stream operations in + * case the contents of the directory can change between opendir + * and releasedir. + * + * Valid replies: + * fuse_reply_open + * fuse_reply_err + * + * @param req request handle + * @param ino the inode number + * @param fi file information + */ + void (*opendir) (fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *fi); + + /** + * Read directory + * + * Send a buffer filled using fuse_add_direntry(), with size not + * exceeding the requested size. Send an empty buffer on end of + * stream. + * + * fi->fh will contain the value set by the opendir method, or + * will be undefined if the opendir method didn't set any value. + * + * Valid replies: + * fuse_reply_buf + * fuse_reply_err + * + * @param req request handle + * @param ino the inode number + * @param size maximum number of bytes to send + * @param off offset to continue reading the directory stream + * @param fi file information + */ + void (*readdir) (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, + struct fuse_file_info *fi); + + /** + * Release an open directory + * + * For every opendir call there will be exactly one releasedir + * call. + * + * fi->fh will contain the value set by the opendir method, or + * will be undefined if the opendir method didn't set any value. + * + * Valid replies: + * fuse_reply_err + * + * @param req request handle + * @param ino the inode number + * @param fi file information + */ + void (*releasedir) (fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *fi); + + /** + * Synchronize directory contents + * + * If the datasync parameter is non-zero, then only the directory + * contents should be flushed, not the meta data. + * + * fi->fh will contain the value set by the opendir method, or + * will be undefined if the opendir method didn't set any value. + * + * Valid replies: + * fuse_reply_err + * + * @param req request handle + * @param ino the inode number + * @param datasync flag indicating if only data should be flushed + * @param fi file information + */ + void (*fsyncdir) (fuse_req_t req, fuse_ino_t ino, int datasync, + struct fuse_file_info *fi); + + /** + * Get file system statistics + * + * Valid replies: + * fuse_reply_statfs + * fuse_reply_err + * + * @param req request handle + * @param ino the inode number, zero means "undefined" + */ + void (*statfs) (fuse_req_t req, fuse_ino_t ino); + + /** + * Set an extended attribute + * + * Valid replies: + * fuse_reply_err + */ + void (*setxattr) (fuse_req_t req, fuse_ino_t ino, const char *name, + const char *value, size_t size, int flags); + + /** + * Get an extended attribute + * + * If size is zero, the size of the value should be sent with + * fuse_reply_xattr. + * + * If the size is non-zero, and the value fits in the buffer, the + * value should be sent with fuse_reply_buf. + * + * If the size is too small for the value, the ERANGE error should + * be sent. + * + * Valid replies: + * fuse_reply_buf + * fuse_reply_xattr + * fuse_reply_err + * + * @param req request handle + * @param ino the inode number + * @param name of the extended attribute + * @param size maximum size of the value to send + */ + void (*getxattr) (fuse_req_t req, fuse_ino_t ino, const char *name, + size_t size); + + /** + * List extended attribute names + * + * If size is zero, the total size of the attribute list should be + * sent with fuse_reply_xattr. + * + * If the size is non-zero, and the null character separated + * attribute list fits in the buffer, the list should be sent with + * fuse_reply_buf. + * + * If the size is too small for the list, the ERANGE error should + * be sent. + * + * Valid replies: + * fuse_reply_buf + * fuse_reply_xattr + * fuse_reply_err + * + * @param req request handle + * @param ino the inode number + * @param size maximum size of the list to send + */ + void (*listxattr) (fuse_req_t req, fuse_ino_t ino, size_t size); + + /** + * Remove an extended attribute + * + * Valid replies: + * fuse_reply_err + * + * @param req request handle + * @param ino the inode number + * @param name of the extended attribute + */ + void (*removexattr) (fuse_req_t req, fuse_ino_t ino, const char *name); + + /** + * Check file access permissions + * + * This will be called for the access() system call. If the + * 'default_permissions' mount option is given, this method is not + * called. + * + * This method is not called under Linux kernel versions 2.4.x + * + * Introduced in version 2.5 + * + * Valid replies: + * fuse_reply_err + * + * @param req request handle + * @param ino the inode number + * @param mask requested access mode + */ + void (*access) (fuse_req_t req, fuse_ino_t ino, int mask); + + /** + * Create and open a file + * + * If the file does not exist, first create it with the specified + * mode, and then open it. + * + * Open flags (with the exception of O_NOCTTY) are available in + * fi->flags. + * + * Filesystem may store an arbitrary file handle (pointer, index, + * etc) in fi->fh, and use this in other all other file operations + * (read, write, flush, release, fsync). + * + * There are also some flags (direct_io, keep_cache) which the + * filesystem may set in fi, to change the way the file is opened. + * See fuse_file_info structure in for more details. + * + * If this method is not implemented or under Linux kernel + * versions earlier than 2.6.15, the mknod() and open() methods + * will be called instead. + * + * Introduced in version 2.5 + * + * Valid replies: + * fuse_reply_create + * fuse_reply_err + * + * @param req request handle + * @param parent inode number of the parent directory + * @param name to create + * @param mode file type and mode with which to create the new file + * @param fi file information + */ + void (*create) (fuse_req_t req, fuse_ino_t parent, const char *name, + mode_t mode, struct fuse_file_info *fi); + + /** + * Test for a POSIX file lock + * + * Introduced in version 2.6 + * + * Valid replies: + * fuse_reply_lock + * fuse_reply_err + * + * @param req request handle + * @param ino the inode number + * @param fi file information + * @param lock the region/type to test + */ + void (*getlk) (fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *fi, struct flock *lock); + + /** + * Acquire, modify or release a POSIX file lock + * + * For POSIX threads (NPTL) there's a 1-1 relation between pid and + * owner, but otherwise this is not always the case. For checking + * lock ownership, 'fi->owner' must be used. The l_pid field in + * 'struct flock' should only be used to fill in this field in + * getlk(). + * + * Note: if the locking methods are not implemented, the kernel + * will still allow file locking to work locally. Hence these are + * only interesting for network filesystems and similar. + * + * Introduced in version 2.6 + * + * Valid replies: + * fuse_reply_err + * + * @param req request handle + * @param ino the inode number + * @param fi file information + * @param lock the region/type to test + * @param sleep locking operation may sleep + */ + void (*setlk) (fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *fi, + struct flock *lock, int sleep); + + /** + * Map block index within file to block index within device + * + * Note: This makes sense only for block device backed filesystems + * mounted with the 'blkdev' option + * + * Introduced in version 2.6 + * + * Valid replies: + * fuse_reply_bmap + * fuse_reply_err + * + * @param req request handle + * @param ino the inode number + * @param blocksize unit of block index + * @param idx block index within file + */ + void (*bmap) (fuse_req_t req, fuse_ino_t ino, size_t blocksize, + uint64_t idx); +}; + +/** + * Reply with an error code or success + * + * Possible requests: + * all except forget + * + * unlink, rmdir, rename, flush, release, fsync, fsyncdir, setxattr, + * removexattr and setlk may send a zero code + * + * @param req request handle + * @param err the positive error value, or zero for success + * @return zero for success, -errno for failure to send reply + */ +int fuse_reply_err(fuse_req_t req, int err); + +/** + * Don't send reply + * + * Possible requests: + * forget + * + * @param req request handle + */ +void fuse_reply_none(fuse_req_t req); + +/** + * Reply with a directory entry + * + * Possible requests: + * lookup, mknod, mkdir, symlink, link + * + * @param req request handle + * @param e the entry parameters + * @return zero for success, -errno for failure to send reply + */ +int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e); + +/** + * Reply with a directory entry and open parameters + * + * currently the following members of 'fi' are used: + * fh, direct_io, keep_cache + * + * Possible requests: + * create + * + * @param req request handle + * @param e the entry parameters + * @param fi file information + * @return zero for success, -errno for failure to send reply + */ +int fuse_reply_create(fuse_req_t req, const struct fuse_entry_param *e, + const struct fuse_file_info *fi); + +/** + * Reply with attributes + * + * Possible requests: + * getattr, setattr + * + * @param req request handle + * @param the attributes + * @param attr_timeout validity timeout (in seconds) for the attributes + * @return zero for success, -errno for failure to send reply + */ +int fuse_reply_attr(fuse_req_t req, const struct stat *attr, + double attr_timeout); + +/** + * Reply with the contents of a symbolic link + * + * Possible requests: + * readlink + * + * @param req request handle + * @param link symbolic link contents + * @return zero for success, -errno for failure to send reply + */ +int fuse_reply_readlink(fuse_req_t req, const char *link); + +/** + * Reply with open parameters + * + * currently the following members of 'fi' are used: + * fh, direct_io, keep_cache + * + * Possible requests: + * open, opendir + * + * @param req request handle + * @param fi file information + * @return zero for success, -errno for failure to send reply + */ +int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *fi); + +/** + * Reply with number of bytes written + * + * Possible requests: + * write + * + * @param req request handle + * @param count the number of bytes written + * @return zero for success, -errno for failure to send reply + */ +int fuse_reply_write(fuse_req_t req, size_t count); + +/** + * Reply with data + * + * Possible requests: + * read, readdir, getxattr, listxattr + * + * @param req request handle + * @param buf buffer containing data + * @param size the size of data in bytes + * @return zero for success, -errno for failure to send reply + */ +int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size); + +#ifdef POSIXACLS +/** + * Reply with data vector + * + * Possible requests: + * read, readdir, getxattr, listxattr + * + * @param req request handle + * @param iov the vector containing the data + * @param count the size of vector + * @return zero for success, -errno for failure to send reply + */ +int fuse_reply_iov(fuse_req_t req, const struct iovec *iov, int count); +#endif + +/** + * Reply with filesystem statistics + * + * Possible requests: + * statfs + * + * @param req request handle + * @param stbuf filesystem statistics + * @return zero for success, -errno for failure to send reply + */ +#if HAVE_SYS_STATVFS_H +int fuse_reply_statfs(fuse_req_t req, const struct statvfs *stbuf); +#endif + + +/** + * Reply with needed buffer size + * + * Possible requests: + * getxattr, listxattr + * + * @param req request handle + * @param count the buffer size needed in bytes + * @return zero for success, -errno for failure to send reply + */ +int fuse_reply_xattr(fuse_req_t req, size_t count); + +/** + * Reply with file lock information + * + * Possible requests: + * getlk + * + * @param req request handle + * @param lock the lock information + * @return zero for success, -errno for failure to send reply + */ +int fuse_reply_lock(fuse_req_t req, struct flock *lock); + +/** + * Reply with block index + * + * Possible requests: + * bmap + * + * @param req request handle + * @param idx block index within device + * @return zero for success, -errno for failure to send reply + */ +int fuse_reply_bmap(fuse_req_t req, uint64_t idx); + +/* ----------------------------------------------------------- * + * Filling a buffer in readdir * + * ----------------------------------------------------------- */ + +/** + * Add a directory entry to the buffer + * + * Buffer needs to be large enough to hold the entry. Of it's not, + * then the entry is not filled in but the size of the entry is still + * returned. The caller can check this by comparing the bufsize + * parameter with the returned entry size. If the entry size is + * larger than the buffer size, the operation failed. + * + * From the 'stbuf' argument the st_ino field and bits 12-15 of the + * st_mode field are used. The other fields are ignored. + * + * Note: offsets do not necessarily represent physical offsets, and + * could be any marker, that enables the implementation to find a + * specific point in the directory stream. + * + * @param req request handle + * @param buf the point where the new entry will be added to the buffer + * @param bufsize remaining size of the buffer + * @param the name of the entry + * @param stbuf the file attributes + * @param off the offset of the next entry + * @return the space needed for the entry + */ +size_t fuse_add_direntry(fuse_req_t req, char *buf, size_t bufsize, + const char *name, const struct stat *stbuf, + off_t off); + +/* ----------------------------------------------------------- * + * Utility functions * + * ----------------------------------------------------------- */ + +/** + * Get the userdata from the request + * + * @param req request handle + * @return the user data passed to fuse_lowlevel_new() + */ +void *fuse_req_userdata(fuse_req_t req); + +/** + * Get the context from the request + * + * The pointer returned by this function will only be valid for the + * request's lifetime + * + * @param req request handle + * @return the context structure + */ +const struct fuse_ctx *fuse_req_ctx(fuse_req_t req); + +/** + * Callback function for an interrupt + * + * @param req interrupted request + * @param data user data + */ +typedef void (*fuse_interrupt_func_t)(fuse_req_t req, void *data); + +/** + * Register/unregister callback for an interrupt + * + * If an interrupt has already happened, then the callback function is + * called from within this function, hence it's not possible for + * interrupts to be lost. + * + * @param req request handle + * @param func the callback function or NULL for unregister + * @parm data user data passed to the callback function + */ +void fuse_req_interrupt_func(fuse_req_t req, fuse_interrupt_func_t func, + void *data); + +/** + * Check if a request has already been interrupted + * + * @param req request handle + * @return 1 if the request has been interrupted, 0 otherwise + */ +int fuse_req_interrupted(fuse_req_t req); + +/* ----------------------------------------------------------- * + * Filesystem setup * + * ----------------------------------------------------------- */ + +/** + * Create a low level session + * + * @param args argument vector + * @param op the low level filesystem operations + * @param op_size sizeof(struct fuse_lowlevel_ops) + * @param userdata user data + * @return the created session object, or NULL on failure + */ +struct fuse_session *fuse_lowlevel_new(struct fuse_args *args, + const struct fuse_lowlevel_ops *op, + size_t op_size, void *userdata); + +/* ----------------------------------------------------------- * + * Session interface * + * ----------------------------------------------------------- */ + +/** + * Session operations + * + * This is used in session creation + */ +struct fuse_session_ops { + /** + * Hook to process a request (mandatory) + * + * @param data user data passed to fuse_session_new() + * @param buf buffer containing the raw request + * @param len request length + * @param ch channel on which the request was received + */ + void (*process) (void *data, const char *buf, size_t len, + struct fuse_chan *ch); + + /** + * Hook for session exit and reset (optional) + * + * @param data user data passed to fuse_session_new() + * @param val exited status (1 - exited, 0 - not exited) + */ + void (*exit) (void *data, int val); + + /** + * Hook for querying the current exited status (optional) + * + * @param data user data passed to fuse_session_new() + * @return 1 if exited, 0 if not exited + */ + int (*exited) (void *data); + + /** + * Hook for cleaning up the channel on destroy (optional) + * + * @param data user data passed to fuse_session_new() + */ + void (*destroy) (void *data); +}; + +/** + * Create a new session + * + * @param op session operations + * @param data user data + * @return new session object, or NULL on failure + */ +struct fuse_session *fuse_session_new(struct fuse_session_ops *op, void *data); + +/** + * Assign a channel to a session + * + * Note: currently only a single channel may be assigned. This may + * change in the future + * + * If a session is destroyed, the assigned channel is also destroyed + * + * @param se the session + * @param ch the channel + */ +void fuse_session_add_chan(struct fuse_session *se, struct fuse_chan *ch); + +/** + * Remove a channel from a session + * + * If the channel is not assigned to a session, then this is a no-op + * + * @param ch the channel to remove + */ +void fuse_session_remove_chan(struct fuse_chan *ch); + +/** + * Iterate over the channels assigned to a session + * + * The iterating function needs to start with a NULL channel, and + * after that needs to pass the previously returned channel to the + * function. + * + * @param se the session + * @param ch the previous channel, or NULL + * @return the next channel, or NULL if no more channels exist + */ +struct fuse_chan *fuse_session_next_chan(struct fuse_session *se, + struct fuse_chan *ch); + +/** + * Process a raw request + * + * @param se the session + * @param buf buffer containing the raw request + * @param len request length + * @param ch channel on which the request was received + */ +void fuse_session_process(struct fuse_session *se, const char *buf, size_t len, + struct fuse_chan *ch); + +/** + * Destroy a session + * + * @param se the session + */ +void fuse_session_destroy(struct fuse_session *se); + +/** + * Exit a session + * + * @param se the session + */ +void fuse_session_exit(struct fuse_session *se); + +/** + * Reset the exited status of a session + * + * @param se the session + */ +void fuse_session_reset(struct fuse_session *se); + +/** + * Query the exited status of a session + * + * @param se the session + * @return 1 if exited, 0 if not exited + */ +int fuse_session_exited(struct fuse_session *se); + +/** + * Enter a single threaded event loop + * + * @param se the session + * @return 0 on success, -1 on error + */ +int fuse_session_loop(struct fuse_session *se); + +/** + * Enter a multi-threaded event loop + * + * @param se the session + * @return 0 on success, -1 on error + */ +int fuse_session_loop_mt(struct fuse_session *se); + +/* ----------------------------------------------------------- * + * Channel interface * + * ----------------------------------------------------------- */ + +/** + * Channel operations + * + * This is used in channel creation + */ +struct fuse_chan_ops { + /** + * Hook for receiving a raw request + * + * @param ch pointer to the channel + * @param buf the buffer to store the request in + * @param size the size of the buffer + * @return the actual size of the raw request, or -1 on error + */ + int (*receive)(struct fuse_chan **chp, char *buf, size_t size); + + /** + * Hook for sending a raw reply + * + * A return value of -ENOENT means, that the request was + * interrupted, and the reply was discarded + * + * @param ch the channel + * @param iov vector of blocks + * @param count the number of blocks in vector + * @return zero on success, -errno on failure + */ + int (*send)(struct fuse_chan *ch, const struct iovec iov[], + size_t count); + + /** + * Destroy the channel + * + * @param ch the channel + */ + void (*destroy)(struct fuse_chan *ch); +}; + +/** + * Create a new channel + * + * @param op channel operations + * @param fd file descriptor of the channel + * @param bufsize the minimal receive buffer size + * @param data user data + * @return the new channel object, or NULL on failure + */ +struct fuse_chan *fuse_chan_new(struct fuse_chan_ops *op, int fd, + size_t bufsize, void *data); + +/** + * Query the file descriptor of the channel + * + * @param ch the channel + * @return the file descriptor passed to fuse_chan_new() + */ +int fuse_chan_fd(struct fuse_chan *ch); + +/** + * Query the minimal receive buffer size + * + * @param ch the channel + * @return the buffer size passed to fuse_chan_new() + */ +size_t fuse_chan_bufsize(struct fuse_chan *ch); + +/** + * Query the user data + * + * @param ch the channel + * @return the user data passed to fuse_chan_new() + */ +void *fuse_chan_data(struct fuse_chan *ch); + +/** + * Query the session to which this channel is assigned + * + * @param ch the channel + * @return the session, or NULL if the channel is not assigned + */ +struct fuse_session *fuse_chan_session(struct fuse_chan *ch); + +/** + * Receive a raw request + * + * A return value of -ENODEV means, that the filesystem was unmounted + * + * @param ch pointer to the channel + * @param buf the buffer to store the request in + * @param size the size of the buffer + * @return the actual size of the raw request, or -errno on error + */ +int fuse_chan_recv(struct fuse_chan **ch, char *buf, size_t size); + +/** + * Send a raw reply + * + * A return value of -ENOENT means, that the request was + * interrupted, and the reply was discarded + * + * @param ch the channel + * @param iov vector of blocks + * @param count the number of blocks in vector + * @return zero on success, -errno on failure + */ +int fuse_chan_send(struct fuse_chan *ch, const struct iovec iov[], + size_t count); + +/** + * Destroy a channel + * + * @param ch the channel + */ +void fuse_chan_destroy(struct fuse_chan *ch); + +#ifdef __cplusplus +} +#endif + +#endif /* _FUSE_LOWLEVEL_H_ */ diff --git a/include/fuse-lite/fuse_lowlevel_compat.h b/include/fuse-lite/fuse_lowlevel_compat.h new file mode 100755 index 0000000..753d46b --- a/dev/null +++ b/include/fuse-lite/fuse_lowlevel_compat.h @@ -0,0 +1,16 @@ +/* + FUSE: Filesystem in Userspace + Copyright (C) 2001-2007 Miklos Szeredi + + This program can be distributed under the terms of the GNU LGPLv2. + See the file COPYING.LIB. +*/ + +/* these definitions provide source compatibility to prior versions. + Do not include this file directly! */ + +size_t fuse_dirent_size(size_t namelen); + +char *fuse_add_dirent(char *buf, const char *name, const struct stat *stbuf, + off_t off); + diff --git a/include/fuse-lite/fuse_opt.h b/include/fuse-lite/fuse_opt.h new file mode 100755 index 0000000..7ae08af --- a/dev/null +++ b/include/fuse-lite/fuse_opt.h @@ -0,0 +1,261 @@ +/* + FUSE: Filesystem in Userspace + Copyright (C) 2001-2007 Miklos Szeredi + + This program can be distributed under the terms of the GNU LGPLv2. + See the file COPYING.LIB. +*/ + +#ifndef _FUSE_OPT_H_ +#define _FUSE_OPT_H_ + +/** @file + * + * This file defines the option parsing interface of FUSE + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Option description + * + * This structure describes a single option, and and action associated + * with it, in case it matches. + * + * More than one such match may occur, in which case the action for + * each match is executed. + * + * There are three possible actions in case of a match: + * + * i) An integer (int or unsigned) variable determined by 'offset' is + * set to 'value' + * + * ii) The processing function is called, with 'value' as the key + * + * iii) An integer (any) or string (char *) variable determined by + * 'offset' is set to the value of an option parameter + * + * 'offset' should normally be either set to + * + * - 'offsetof(struct foo, member)' actions i) and iii) + * + * - -1 action ii) + * + * The 'offsetof()' macro is defined in the header. + * + * The template determines which options match, and also have an + * effect on the action. Normally the action is either i) or ii), but + * if a format is present in the template, then action iii) is + * performed. + * + * The types of templates are: + * + * 1) "-x", "-foo", "--foo", "--foo-bar", etc. These match only + * themselves. Invalid values are "--" and anything beginning + * with "-o" + * + * 2) "foo", "foo-bar", etc. These match "-ofoo", "-ofoo-bar" or + * the relevant option in a comma separated option list + * + * 3) "bar=", "--foo=", etc. These are variations of 1) and 2) + * which have a parameter + * + * 4) "bar=%s", "--foo=%lu", etc. Same matching as above but perform + * action iii). + * + * 5) "-x ", etc. Matches either "-xparam" or "-x param" as + * two separate arguments + * + * 6) "-x %s", etc. Combination of 4) and 5) + * + * If the format is "%s", memory is allocated for the string unlike + * with scanf(). + */ +struct fuse_opt { + /** Matching template and optional parameter formatting */ + const char *templ; + + /** + * Offset of variable within 'data' parameter of fuse_opt_parse() + * or -1 + */ + unsigned long offset; + + /** + * Value to set the variable to, or to be passed as 'key' to the + * processing function. Ignored if template has a format + */ + int value; +}; + +/** + * Key option. In case of a match, the processing function will be + * called with the specified key. + */ +#define FUSE_OPT_KEY(templ, key) { templ, -1U, key } + +/** + * Last option. An array of 'struct fuse_opt' must end with a NULL + * template value + */ +#define FUSE_OPT_END { .templ = NULL } + +/** + * Argument list + */ +struct fuse_args { + /** Argument count */ + int argc; + + /** Argument vector. NULL terminated */ + char **argv; + + /** Is 'argv' allocated? */ + int allocated; +}; + +/** + * Initializer for 'struct fuse_args' + */ +#define FUSE_ARGS_INIT(argc, argv) { argc, argv, 0 } + +/** + * Key value passed to the processing function if an option did not + * match any template + */ +#define FUSE_OPT_KEY_OPT -1 + +/** + * Key value passed to the processing function for all non-options + * + * Non-options are the arguments beginning with a charater other than + * '-' or all arguments after the special '--' option + */ +#define FUSE_OPT_KEY_NONOPT -2 + +/** + * Special key value for options to keep + * + * Argument is not passed to processing function, but behave as if the + * processing function returned 1 + */ +#define FUSE_OPT_KEY_KEEP -3 + +/** + * Special key value for options to discard + * + * Argument is not passed to processing function, but behave as if the + * processing function returned zero + */ +#define FUSE_OPT_KEY_DISCARD -4 + +/** + * Processing function + * + * This function is called if + * - option did not match any 'struct fuse_opt' + * - argument is a non-option + * - option did match and offset was set to -1 + * + * The 'arg' parameter will always contain the whole argument or + * option including the parameter if exists. A two-argument option + * ("-x foo") is always converted to single arguemnt option of the + * form "-xfoo" before this function is called. + * + * Options of the form '-ofoo' are passed to this function without the + * '-o' prefix. + * + * The return value of this function determines whether this argument + * is to be inserted into the output argument vector, or discarded. + * + * @param data is the user data passed to the fuse_opt_parse() function + * @param arg is the whole argument or option + * @param key determines why the processing function was called + * @param outargs the current output argument list + * @return -1 on error, 0 if arg is to be discarded, 1 if arg should be kept + */ +typedef int (*fuse_opt_proc_t)(void *data, const char *arg, int key, + struct fuse_args *outargs); + +/** + * Option parsing function + * + * If 'args' was returned from a previous call to fuse_opt_parse() or + * it was constructed from + * + * A NULL 'args' is equivalent to an empty argument vector + * + * A NULL 'opts' is equivalent to an 'opts' array containing a single + * end marker + * + * A NULL 'proc' is equivalent to a processing function always + * returning '1' + * + * @param args is the input and output argument list + * @param data is the user data + * @param opts is the option description array + * @param proc is the processing function + * @return -1 on error, 0 on success + */ +int fuse_opt_parse(struct fuse_args *args, void *data, + const struct fuse_opt opts[], fuse_opt_proc_t proc); + +/** + * Add an option to a comma separated option list + * + * @param opts is a pointer to an option list, may point to a NULL value + * @param opt is the option to add + * @return -1 on allocation error, 0 on success + */ +int fuse_opt_add_opt(char **opts, const char *opt); + +/** + * Add an argument to a NULL terminated argument vector + * + * @param args is the structure containing the current argument list + * @param arg is the new argument to add + * @return -1 on allocation error, 0 on success + */ +int fuse_opt_add_arg(struct fuse_args *args, const char *arg); + +/** + * Add an argument at the specified position in a NULL terminated + * argument vector + * + * Adds the argument to the N-th position. This is useful for adding + * options at the beggining of the array which must not come after the + * special '--' option. + * + * @param args is the structure containing the current argument list + * @param pos is the position at which to add the argument + * @param arg is the new argument to add + * @return -1 on allocation error, 0 on success + */ +int fuse_opt_insert_arg(struct fuse_args *args, int pos, const char *arg); + +/** + * Free the contents of argument list + * + * The structure itself is not freed + * + * @param args is the structure containing the argument list + */ +void fuse_opt_free_args(struct fuse_args *args); + + +/** + * Check if an option matches + * + * @param opts is the option description array + * @param opt is the option to match + * @return 1 if a match is found, 0 if not + */ +int fuse_opt_match(const struct fuse_opt opts[], const char *opt); + +#ifdef __cplusplus +} +#endif + +#endif /* _FUSE_OPT_H_ */ diff --git a/include/ntfs-3g/Makefile.am b/include/ntfs-3g/Makefile.am new file mode 100755 index 0000000..f4f72d6 --- a/dev/null +++ b/include/ntfs-3g/Makefile.am @@ -0,0 +1,45 @@ + +MAINTAINERCLEANFILES = $(srcdir)/Makefile.in + +headers = \ + acls.h \ + attrib.h \ + attrlist.h \ + bitmap.h \ + bootsect.h \ + cache.h \ + collate.h \ + compat.h \ + compress.h \ + debug.h \ + device.h \ + device_io.h \ + dir.h \ + efs.h \ + endians.h \ + index.h \ + inode.h \ + layout.h \ + lcnalloc.h \ + logfile.h \ + logging.h \ + mft.h \ + misc.h \ + mst.h \ + ntfstime.h \ + object_id.h \ + param.h \ + reparse.h \ + runlist.h \ + security.h \ + support.h \ + types.h \ + unistr.h \ + volume.h + +if INSTALL_LIBRARY +ntfs3ginclude_HEADERS = $(headers) +else +noinst_HEADERS = $(headers) +endif + diff --git a/include/ntfs-3g/Makefile.in b/include/ntfs-3g/Makefile.in new file mode 100755 index 0000000..fc65201 --- a/dev/null +++ b/include/ntfs-3g/Makefile.in @@ -0,0 +1,471 @@ +# Makefile.in generated by automake 1.10.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008 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@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@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 = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +subdir = include/ntfs-3g +DIST_COMMON = $(am__noinst_HEADERS_DIST) \ + $(am__ntfs3ginclude_HEADERS_DIST) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +SOURCES = +DIST_SOURCES = +am__noinst_HEADERS_DIST = acls.h attrib.h attrlist.h bitmap.h \ + bootsect.h cache.h collate.h compat.h compress.h debug.h \ + device.h device_io.h dir.h efs.h endians.h index.h inode.h \ + layout.h lcnalloc.h logfile.h logging.h mft.h misc.h mst.h \ + ntfstime.h object_id.h param.h reparse.h runlist.h security.h \ + support.h types.h unistr.h volume.h +am__ntfs3ginclude_HEADERS_DIST = acls.h attrib.h attrlist.h bitmap.h \ + bootsect.h cache.h collate.h compat.h compress.h debug.h \ + device.h device_io.h dir.h efs.h endians.h index.h inode.h \ + layout.h lcnalloc.h logfile.h logging.h mft.h misc.h mst.h \ + ntfstime.h object_id.h param.h reparse.h runlist.h security.h \ + support.h types.h unistr.h volume.h +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 = `echo $$p | sed -e 's|^.*/||'`; +am__installdirs = "$(DESTDIR)$(ntfs3gincludedir)" +ntfs3gincludeHEADERS_INSTALL = $(INSTALL_HEADER) +HEADERS = $(noinst_HEADERS) $(ntfs3ginclude_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DSYMUTIL = @DSYMUTIL@ +ECHO = @ECHO@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +F77 = @F77@ +FFLAGS = @FFLAGS@ +FUSE_MODULE_CFLAGS = @FUSE_MODULE_CFLAGS@ +FUSE_MODULE_LIBS = @FUSE_MODULE_LIBS@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDCONFIG = @LDCONFIG@ +LDFLAGS = @LDFLAGS@ +LIBFUSE_LITE_LIBS = @LIBFUSE_LITE_LIBS@ +LIBNTFS_3G_VERSION = @LIBNTFS_3G_VERSION@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MV = @MV@ +NMEDIT = @NMEDIT@ +OBJEXT = @OBJEXT@ +OUTPUT_FORMAT = @OUTPUT_FORMAT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PKG_CONFIG = @PKG_CONFIG@ +RANLIB = @RANLIB@ +RM = @RM@ +SED = @SED@ +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_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_F77 = @ac_ct_F77@ +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 = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +ntfs3gincludedir = @ntfs3gincludedir@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgconfigdir = @pkgconfigdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +rootbindir = @rootbindir@ +rootlibdir = @rootlibdir@ +rootsbindir = @rootsbindir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +MAINTAINERCLEANFILES = $(srcdir)/Makefile.in +headers = \ + acls.h \ + attrib.h \ + attrlist.h \ + bitmap.h \ + bootsect.h \ + cache.h \ + collate.h \ + compat.h \ + compress.h \ + debug.h \ + device.h \ + device_io.h \ + dir.h \ + efs.h \ + endians.h \ + index.h \ + inode.h \ + layout.h \ + lcnalloc.h \ + logfile.h \ + logging.h \ + mft.h \ + misc.h \ + mst.h \ + ntfstime.h \ + object_id.h \ + param.h \ + reparse.h \ + runlist.h \ + security.h \ + support.h \ + types.h \ + unistr.h \ + volume.h + +@INSTALL_LIBRARY_TRUE@ntfs3ginclude_HEADERS = $(headers) +@INSTALL_LIBRARY_FALSE@noinst_HEADERS = $(headers) +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu include/ntfs-3g/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu include/ntfs-3g/Makefile +.PRECIOUS: 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__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-ntfs3gincludeHEADERS: $(ntfs3ginclude_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(ntfs3gincludedir)" || $(MKDIR_P) "$(DESTDIR)$(ntfs3gincludedir)" + @list='$(ntfs3ginclude_HEADERS)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f=$(am__strip_dir) \ + echo " $(ntfs3gincludeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(ntfs3gincludedir)/$$f'"; \ + $(ntfs3gincludeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(ntfs3gincludedir)/$$f"; \ + done + +uninstall-ntfs3gincludeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(ntfs3ginclude_HEADERS)'; for p in $$list; do \ + f=$(am__strip_dir) \ + echo " rm -f '$(DESTDIR)$(ntfs3gincludedir)/$$f'"; \ + rm -f "$(DESTDIR)$(ntfs3gincludedir)/$$f"; \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(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 $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$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 $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(ntfs3gincludedir)"; 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: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) +clean: clean-am + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-ntfs3gincludeHEADERS + +install-dvi: install-dvi-am + +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 + +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 mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-ntfs3gincludeHEADERS + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool ctags distclean distclean-generic \ + distclean-libtool 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-ntfs3gincludeHEADERS \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-ntfs3gincludeHEADERS + +# 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: diff --git a/include/ntfs-3g/acls.h b/include/ntfs-3g/acls.h new file mode 100755 index 0000000..8a83d32 --- a/dev/null +++ b/include/ntfs-3g/acls.h @@ -0,0 +1,199 @@ +/* + * + * Copyright (c) 2007-2008 Jean-Pierre Andre + * + */ + +/* + * 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 (in the main directory of the NTFS-3G + * distribution in the file COPYING); if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef ACLS_H +#define ACLS_H + +/* + * JPA configuration modes for security.c / acls.c + * should be moved to some config file + */ + +#define BUFSZ 1024 /* buffer size to read mapping file */ +#define MAPPINGFILE ".NTFS-3G/UserMapping" /* default mapping file */ +#define LINESZ 120 /* maximum useful size of a mapping line */ +#define CACHE_PERMISSIONS_BITS 6 /* log2 of unitary allocation of permissions */ +#define CACHE_PERMISSIONS_SIZE 262144 /* max cacheable permissions */ + +/* + * JPA The following must be in some library... + * but did not found out where + */ + +#define endian_rev16(x) (((x >> 8) & 255) | ((x & 255) << 8)) +#define endian_rev32(x) (((x >> 24) & 255) | ((x >> 8) & 0xff00) \ + | ((x & 0xff00) << 8) | ((x & 255) << 24)) + +#define cpu_to_be16(x) endian_rev16(cpu_to_le16(x)) +#define cpu_to_be32(x) endian_rev32(cpu_to_le32(x)) + +/* + * Macro definitions needed to share code with secaudit + */ + +#define NTFS_FIND_USID(map,uid,buf) ntfs_find_usid(map,uid,buf) +#define NTFS_FIND_GSID(map,gid,buf) ntfs_find_gsid(map,gid,buf) +#define NTFS_FIND_USER(map,usid) ntfs_find_user(map,usid) +#define NTFS_FIND_GROUP(map,gsid) ntfs_find_group(map,gsid) + + +/* + * Matching of ntfs permissions to Linux permissions + * these constants are adapted to endianness + * when setting, set them all + * when checking, check one is present + */ + + /* flags which are set to mean exec, write or read */ + +#define FILE_READ (FILE_READ_DATA) +#define FILE_WRITE (FILE_WRITE_DATA | FILE_APPEND_DATA \ + | READ_CONTROL | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA) +#define FILE_EXEC (FILE_EXECUTE) +#define DIR_READ FILE_LIST_DIRECTORY +#define DIR_WRITE (FILE_ADD_FILE | FILE_ADD_SUBDIRECTORY | FILE_DELETE_CHILD \ + | READ_CONTROL | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA) +#define DIR_EXEC (FILE_TRAVERSE) + + /* flags tested for meaning exec, write or read */ + /* tests for write allow for interpretation of a sticky bit */ + +#define FILE_GREAD (FILE_READ_DATA | GENERIC_READ) +#define FILE_GWRITE (FILE_WRITE_DATA | FILE_APPEND_DATA | GENERIC_WRITE) +#define FILE_GEXEC (FILE_EXECUTE | GENERIC_EXECUTE) +#define DIR_GREAD (FILE_LIST_DIRECTORY | GENERIC_READ) +#define DIR_GWRITE (FILE_ADD_FILE | FILE_ADD_SUBDIRECTORY | GENERIC_WRITE) +#define DIR_GEXEC (FILE_TRAVERSE | GENERIC_EXECUTE) + + /* standard owner (and administrator) rights */ + +#define OWNER_RIGHTS (DELETE | READ_CONTROL | WRITE_DAC | WRITE_OWNER \ + | SYNCHRONIZE \ + | FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES \ + | FILE_READ_EA | FILE_WRITE_EA) + + /* standard world rights */ + +#define WORLD_RIGHTS (READ_CONTROL | FILE_READ_ATTRIBUTES | FILE_READ_EA \ + | SYNCHRONIZE) + + /* inheritance flags for files and directories */ + +#define FILE_INHERITANCE NO_PROPAGATE_INHERIT_ACE +#define DIR_INHERITANCE (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE) + +/* + * To identify NTFS ACL meaning Posix ACL granted to root + * we use rights always granted to anybody, so they have no impact + * either on Windows or on Linux. + */ + +#define ROOT_OWNER_UNMARK SYNCHRONIZE /* ACL granted to root as owner */ +#define ROOT_GROUP_UNMARK FILE_READ_EA /* ACL granted to root as group */ + +/* + * A type large enough to hold any SID + */ + +typedef char BIGSID[40]; + +/* + * Struct to hold the input mapping file + * (private to this module) + */ + +struct MAPLIST { + struct MAPLIST *next; + char *uidstr; /* uid text from the same record */ + char *gidstr; /* gid text from the same record */ + char *sidstr; /* sid text from the same record */ + char maptext[LINESZ + 1]; +}; + +typedef int (*FILEREADER)(void *fileid, char *buf, size_t size, off_t pos); + +/* + * Constants defined in acls.c + */ + +extern const SID *adminsid; +extern const SID *worldsid; + +/* + * Functions defined in acls.c + */ + +BOOL ntfs_valid_descr(const char *securattr, unsigned int attrsz); +BOOL ntfs_valid_pattern(const SID *sid); +BOOL ntfs_valid_sid(const SID *sid); +BOOL ntfs_same_sid(const SID *first, const SID *second); + +BOOL ntfs_is_user_sid(const SID *usid); + + +int ntfs_sid_size(const SID * sid); +unsigned int ntfs_attr_size(const char *attr); + +const SID *ntfs_find_usid(const struct MAPPING *usermapping, + uid_t uid, SID *pdefsid); +const SID *ntfs_find_gsid(const struct MAPPING *groupmapping, + gid_t gid, SID *pdefsid); +uid_t ntfs_find_user(const struct MAPPING *usermapping, const SID *usid); +gid_t ntfs_find_group(const struct MAPPING *groupmapping, const SID * gsid); +const SID *ntfs_acl_owner(const char *secattr); + +#if POSIXACLS + +BOOL ntfs_valid_posix(const struct POSIX_SECURITY *pxdesc); +void ntfs_sort_posix(struct POSIX_SECURITY *pxdesc); +int ntfs_merge_mode_posix(struct POSIX_SECURITY *pxdesc, mode_t mode); +struct POSIX_SECURITY *ntfs_build_inherited_posix( + const struct POSIX_SECURITY *pxdesc, mode_t mode, + mode_t umask, BOOL isdir); +struct POSIX_SECURITY *ntfs_replace_acl(const struct POSIX_SECURITY *oldpxdesc, + const struct POSIX_ACL *newacl, int count, BOOL deflt); +struct POSIX_SECURITY *ntfs_build_permissions_posix( + struct MAPPING* const mapping[], + const char *securattr, + const SID *usid, const SID *gsid, BOOL isdir); +struct POSIX_SECURITY *ntfs_merge_descr_posix(const struct POSIX_SECURITY *first, + const struct POSIX_SECURITY *second); +char *ntfs_build_descr_posix(struct MAPPING* const mapping[], + struct POSIX_SECURITY *pxdesc, + int isdir, const SID *usid, const SID *gsid); + +#endif /* POSIXACLS */ + +int ntfs_inherit_acl(const ACL *oldacl, ACL *newacl, + const SID *usid, const SID *gsid, BOOL fordir); +int ntfs_build_permissions(const char *securattr, + const SID *usid, const SID *gsid, BOOL isdir); +char *ntfs_build_descr(mode_t mode, + int isdir, const SID * usid, const SID * gsid); +struct MAPLIST *ntfs_read_mapping(FILEREADER reader, void *fileid); +struct MAPPING *ntfs_do_user_mapping(struct MAPLIST *firstitem); +struct MAPPING *ntfs_do_group_mapping(struct MAPLIST *firstitem); +void ntfs_free_mapping(struct MAPPING *mapping[]); + +#endif /* ACLS_H */ + diff --git a/include/ntfs-3g/attrib.h b/include/ntfs-3g/attrib.h new file mode 100755 index 0000000..bcdb011 --- a/dev/null +++ b/include/ntfs-3g/attrib.h @@ -0,0 +1,358 @@ +/* + * attrib.h - Exports for attribute handling. Originated from the Linux-NTFS project. + * + * Copyright (c) 2000-2004 Anton Altaparmakov + * Copyright (c) 2004-2005 Yura Pakhuchiy + * Copyright (c) 2006-2007 Szabolcs Szakacsits + * + * This program/include file 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/include file 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 (in the main directory of the NTFS-3G + * distribution in the file COPYING); if not, write to the Free Software + * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _NTFS_ATTRIB_H +#define _NTFS_ATTRIB_H + +/* Forward declarations */ +typedef struct _ntfs_attr ntfs_attr; +typedef struct _ntfs_attr_search_ctx ntfs_attr_search_ctx; + +#include "types.h" +#include "inode.h" +#include "unistr.h" +#include "runlist.h" +#include "volume.h" +#include "debug.h" +#include "logging.h" + +extern ntfschar AT_UNNAMED[]; +extern ntfschar STREAM_SDS[]; + +/* The little endian Unicode string $TXF_DATA as a global constant. */ +extern ntfschar TXF_DATA[10]; + +/** + * enum ntfs_lcn_special_values - special return values for ntfs_*_vcn_to_lcn() + * + * Special return values for ntfs_rl_vcn_to_lcn() and ntfs_attr_vcn_to_lcn(). + * + * TODO: Describe them. + */ +typedef enum { + LCN_HOLE = -1, /* Keep this as highest value or die! */ + LCN_RL_NOT_MAPPED = -2, + LCN_ENOENT = -3, + LCN_EINVAL = -4, + LCN_EIO = -5, +} ntfs_lcn_special_values; + +/** + * struct ntfs_attr_search_ctx - search context used in attribute search functions + * @mrec: buffer containing mft record to search + * @attr: attribute record in @mrec where to begin/continue search + * @is_first: if true lookup_attr() begins search with @attr, else after @attr + * + * Structure must be initialized to zero before the first call to one of the + * attribute search functions. Initialize @mrec to point to the mft record to + * search, and @attr to point to the first attribute within @mrec (not necessary + * if calling the _first() functions), and set @is_first to TRUE (not necessary + * if calling the _first() functions). + * + * If @is_first is TRUE, the search begins with @attr. If @is_first is FALSE, + * the search begins after @attr. This is so that, after the first call to one + * of the search attribute functions, we can call the function again, without + * any modification of the search context, to automagically get the next + * matching attribute. + */ +struct _ntfs_attr_search_ctx { + MFT_RECORD *mrec; + ATTR_RECORD *attr; + BOOL is_first; + ntfs_inode *ntfs_ino; + ATTR_LIST_ENTRY *al_entry; + ntfs_inode *base_ntfs_ino; + MFT_RECORD *base_mrec; + ATTR_RECORD *base_attr; +}; + +extern void ntfs_attr_reinit_search_ctx(ntfs_attr_search_ctx *ctx); +extern ntfs_attr_search_ctx *ntfs_attr_get_search_ctx(ntfs_inode *ni, + MFT_RECORD *mrec); +extern void ntfs_attr_put_search_ctx(ntfs_attr_search_ctx *ctx); + +extern int ntfs_attr_lookup(const ATTR_TYPES type, const ntfschar *name, + const u32 name_len, const IGNORE_CASE_BOOL ic, + const VCN lowest_vcn, const u8 *val, const u32 val_len, + ntfs_attr_search_ctx *ctx); + +extern int ntfs_attr_position(const ATTR_TYPES type, ntfs_attr_search_ctx *ctx); + +extern ATTR_DEF *ntfs_attr_find_in_attrdef(const ntfs_volume *vol, + const ATTR_TYPES type); + +/** + * ntfs_attrs_walk - syntactic sugar for walking all attributes in an inode + * @ctx: initialised attribute search context + * + * Syntactic sugar for walking attributes in an inode. + * + * Return 0 on success and -1 on error with errno set to the error code from + * ntfs_attr_lookup(). + * + * Example: When you want to enumerate all attributes in an open ntfs inode + * @ni, you can simply do: + * + * int err; + * ntfs_attr_search_ctx *ctx = ntfs_attr_get_search_ctx(ni, NULL); + * if (!ctx) + * // Error code is in errno. Handle this case. + * while (!(err = ntfs_attrs_walk(ctx))) { + * ATTR_RECORD *attr = ctx->attr; + * // attr now contains the next attribute. Do whatever you want + * // with it and then just continue with the while loop. + * } + * if (err && errno != ENOENT) + * // Ooops. An error occurred! You should handle this case. + * // Now finished with all attributes in the inode. + */ +static __inline__ int ntfs_attrs_walk(ntfs_attr_search_ctx *ctx) +{ + return ntfs_attr_lookup(AT_UNUSED, NULL, 0, CASE_SENSITIVE, 0, + NULL, 0, ctx); +} + +/** + * struct ntfs_attr - ntfs in memory non-resident attribute structure + * @rl: if not NULL, the decompressed runlist + * @ni: base ntfs inode to which this attribute belongs + * @type: attribute type + * @name: Unicode name of the attribute + * @name_len: length of @name in Unicode characters + * @state: NTFS attribute specific flags describing this attribute + * @allocated_size: copy from the attribute record + * @data_size: copy from the attribute record + * @initialized_size: copy from the attribute record + * @compressed_size: copy from the attribute record + * @compression_block_size: size of a compression block (cb) + * @compression_block_size_bits: log2 of the size of a cb + * @compression_block_clusters: number of clusters per cb + * + * This structure exists purely to provide a mechanism of caching the runlist + * of an attribute. If you want to operate on a particular attribute extent, + * you should not be using this structure at all. If you want to work with a + * resident attribute, you should not be using this structure at all. As a + * fail-safe check make sure to test NAttrNonResident() and if it is false, you + * know you shouldn't be using this structure. + * + * If you want to work on a resident attribute or on a specific attribute + * extent, you should use ntfs_lookup_attr() to retrieve the attribute (extent) + * record, edit that, and then write back the mft record (or set the + * corresponding ntfs inode dirty for delayed write back). + * + * @rl is the decompressed runlist of the attribute described by this + * structure. Obviously this only makes sense if the attribute is not resident, + * i.e. NAttrNonResident() is true. If the runlist hasn't been decompressed yet + * @rl is NULL, so be prepared to cope with @rl == NULL. + * + * @ni is the base ntfs inode of the attribute described by this structure. + * + * @type is the attribute type (see layout.h for the definition of ATTR_TYPES), + * @name and @name_len are the little endian Unicode name and the name length + * in Unicode characters of the attribute, respectively. + * + * @state contains NTFS attribute specific flags describing this attribute + * structure. See ntfs_attr_state_bits above. + */ +struct _ntfs_attr { + runlist_element *rl; + ntfs_inode *ni; + ATTR_TYPES type; + ATTR_FLAGS data_flags; + ntfschar *name; + u32 name_len; + unsigned long state; + s64 allocated_size; + s64 data_size; + s64 initialized_size; + s64 compressed_size; + u32 compression_block_size; + u8 compression_block_size_bits; + u8 compression_block_clusters; +}; + +/** + * enum ntfs_attr_state_bits - bits for the state field in the ntfs_attr + * structure + */ +typedef enum { + NA_Initialized, /* 1: structure is initialized. */ + NA_NonResident, /* 1: Attribute is not resident. */ +} ntfs_attr_state_bits; + +#define test_nattr_flag(na, flag) test_bit(NA_##flag, (na)->state) +#define set_nattr_flag(na, flag) set_bit(NA_##flag, (na)->state) +#define clear_nattr_flag(na, flag) clear_bit(NA_##flag, (na)->state) + +#define NAttrInitialized(na) test_nattr_flag(na, Initialized) +#define NAttrSetInitialized(na) set_nattr_flag(na, Initialized) +#define NAttrClearInitialized(na) clear_nattr_flag(na, Initialized) + +#define NAttrNonResident(na) test_nattr_flag(na, NonResident) +#define NAttrSetNonResident(na) set_nattr_flag(na, NonResident) +#define NAttrClearNonResident(na) clear_nattr_flag(na, NonResident) + +#define GenNAttrIno(func_name, flag) \ +extern int NAttr##func_name(ntfs_attr *na); \ +extern void NAttrSet##func_name(ntfs_attr *na); \ +extern void NAttrClear##func_name(ntfs_attr *na); + +GenNAttrIno(Compressed, FILE_ATTR_COMPRESSED) +GenNAttrIno(Encrypted, FILE_ATTR_ENCRYPTED) +GenNAttrIno(Sparse, FILE_ATTR_SPARSE_FILE) +#undef GenNAttrIno + +/** + * union attr_val - Union of all known attribute values + * + * For convenience. Used in the attr structure. + */ +typedef union { + u8 _default; /* Unnamed u8 to serve as default when just using + a_val without specifying any of the below. */ + STANDARD_INFORMATION std_inf; + ATTR_LIST_ENTRY al_entry; + FILE_NAME_ATTR filename; + OBJECT_ID_ATTR obj_id; + SECURITY_DESCRIPTOR_ATTR sec_desc; + VOLUME_NAME vol_name; + VOLUME_INFORMATION vol_inf; + DATA_ATTR data; + INDEX_ROOT index_root; + INDEX_BLOCK index_blk; + BITMAP_ATTR bmp; + REPARSE_POINT reparse; + EA_INFORMATION ea_inf; + EA_ATTR ea; + PROPERTY_SET property_set; + LOGGED_UTILITY_STREAM logged_util_stream; + EFS_ATTR_HEADER efs; +} attr_val; + +extern void ntfs_attr_init(ntfs_attr *na, const BOOL non_resident, + const ATTR_FLAGS data_flags, const BOOL encrypted, + const BOOL sparse, + const s64 allocated_size, const s64 data_size, + const s64 initialized_size, const s64 compressed_size, + const u8 compression_unit); + + /* warning : in the following "name" has to be freeable */ + /* or one of constants AT_UNNAMED, NTFS_INDEX_I30 or STREAM_SDS */ +extern ntfs_attr *ntfs_attr_open(ntfs_inode *ni, const ATTR_TYPES type, + ntfschar *name, u32 name_len); +extern void ntfs_attr_close(ntfs_attr *na); + +extern s64 ntfs_attr_pread(ntfs_attr *na, const s64 pos, s64 count, + void *b); +extern s64 ntfs_attr_pwrite(ntfs_attr *na, const s64 pos, s64 count, + const void *b); +extern int ntfs_attr_pclose(ntfs_attr *na); + +extern void *ntfs_attr_readall(ntfs_inode *ni, const ATTR_TYPES type, + ntfschar *name, u32 name_len, s64 *data_size); + +extern s64 ntfs_attr_mst_pread(ntfs_attr *na, const s64 pos, + const s64 bk_cnt, const u32 bk_size, void *dst); +extern s64 ntfs_attr_mst_pwrite(ntfs_attr *na, const s64 pos, + s64 bk_cnt, const u32 bk_size, void *src); + +extern int ntfs_attr_map_runlist(ntfs_attr *na, VCN vcn); +extern int ntfs_attr_map_whole_runlist(ntfs_attr *na); + +extern LCN ntfs_attr_vcn_to_lcn(ntfs_attr *na, const VCN vcn); +extern runlist_element *ntfs_attr_find_vcn(ntfs_attr *na, const VCN vcn); + +extern int ntfs_attr_size_bounds_check(const ntfs_volume *vol, + const ATTR_TYPES type, const s64 size); +extern int ntfs_attr_can_be_resident(const ntfs_volume *vol, + const ATTR_TYPES type); +int ntfs_attr_make_non_resident(ntfs_attr *na, + ntfs_attr_search_ctx *ctx); +extern int ntfs_make_room_for_attr(MFT_RECORD *m, u8 *pos, u32 size); + +extern int ntfs_resident_attr_record_add(ntfs_inode *ni, ATTR_TYPES type, + ntfschar *name, u8 name_len, u8 *val, u32 size, + ATTR_FLAGS flags); +extern int ntfs_non_resident_attr_record_add(ntfs_inode *ni, ATTR_TYPES type, + ntfschar *name, u8 name_len, VCN lowest_vcn, int dataruns_size, + ATTR_FLAGS flags); +extern int ntfs_attr_record_rm(ntfs_attr_search_ctx *ctx); + +extern int ntfs_attr_add(ntfs_inode *ni, ATTR_TYPES type, + ntfschar *name, u8 name_len, u8 *val, s64 size); +extern int ntfs_attr_set_flags(ntfs_inode *ni, ATTR_TYPES type, + ntfschar *name, u8 name_len, ATTR_FLAGS flags, ATTR_FLAGS mask); +extern int ntfs_attr_rm(ntfs_attr *na); + +extern int ntfs_attr_record_resize(MFT_RECORD *m, ATTR_RECORD *a, u32 new_size); + +extern int ntfs_resident_attr_value_resize(MFT_RECORD *m, ATTR_RECORD *a, + const u32 new_size); + +extern int ntfs_attr_record_move_to(ntfs_attr_search_ctx *ctx, ntfs_inode *ni); +extern int ntfs_attr_record_move_away(ntfs_attr_search_ctx *ctx, int extra); + +extern int ntfs_attr_update_mapping_pairs(ntfs_attr *na, VCN from_vcn); + +extern int ntfs_attr_truncate(ntfs_attr *na, const s64 newsize); + +/** + * get_attribute_value_length - return the length of the value of an attribute + * @a: pointer to a buffer containing the attribute record + * + * Return the byte size of the attribute value of the attribute @a (as it + * would be after eventual decompression and filling in of holes if sparse). + * If we return 0, check errno. If errno is 0 the actual length was 0, + * otherwise errno describes the error. + * + * FIXME: Describe possible errnos. + */ +extern s64 ntfs_get_attribute_value_length(const ATTR_RECORD *a); + +/** + * get_attribute_value - return the attribute value of an attribute + * @vol: volume on which the attribute is present + * @a: attribute to get the value of + * @b: destination buffer for the attribute value + * + * Make a copy of the attribute value of the attribute @a into the destination + * buffer @b. Note, that the size of @b has to be at least equal to the value + * returned by get_attribute_value_length(@a). + * + * Return number of bytes copied. If this is zero check errno. If errno is 0 + * then nothing was read due to a zero-length attribute value, otherwise + * errno describes the error. + */ +extern s64 ntfs_get_attribute_value(const ntfs_volume *vol, + const ATTR_RECORD *a, u8 *b); + +extern void ntfs_attr_name_free(char **name); +extern char *ntfs_attr_name_get(const ntfschar *uname, const int uname_len); +extern int ntfs_attr_exist(ntfs_inode *ni, const ATTR_TYPES type, + ntfschar *name, u32 name_len); +extern int ntfs_attr_remove(ntfs_inode *ni, const ATTR_TYPES type, + ntfschar *name, u32 name_len); +extern s64 ntfs_attr_get_free_bits(ntfs_attr *na); + +#endif /* defined _NTFS_ATTRIB_H */ + diff --git a/include/ntfs-3g/attrlist.h b/include/ntfs-3g/attrlist.h new file mode 100755 index 0000000..2952e48 --- a/dev/null +++ b/include/ntfs-3g/attrlist.h @@ -0,0 +1,51 @@ +/* + * attrlist.h - Exports for attribute list attribute handling. + * Originated from Linux-NTFS project. + * + * Copyright (c) 2004 Anton Altaparmakov + * Copyright (c) 2004 Yura Pakhuchiy + * + * This program/include file 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/include file 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 (in the main directory of the NTFS-3G + * distribution in the file COPYING); if not, write to the Free Software + * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _NTFS_ATTRLIST_H +#define _NTFS_ATTRLIST_H + +#include "attrib.h" + +extern int ntfs_attrlist_need(ntfs_inode *ni); + +extern int ntfs_attrlist_entry_add(ntfs_inode *ni, ATTR_RECORD *attr); +extern int ntfs_attrlist_entry_rm(ntfs_attr_search_ctx *ctx); + +/** + * ntfs_attrlist_mark_dirty - set the attribute list dirty + * @ni: ntfs inode which base inode contain dirty attribute list + * + * Set the attribute list dirty so it is written out later (at the latest at + * ntfs_inode_close() time). + * + * This function cannot fail. + */ +static __inline__ void ntfs_attrlist_mark_dirty(ntfs_inode *ni) +{ + if (ni->nr_extents == -1) + NInoAttrListSetDirty(ni->base_ni); + else + NInoAttrListSetDirty(ni); +} + +#endif /* defined _NTFS_ATTRLIST_H */ diff --git a/include/ntfs-3g/bitmap.h b/include/ntfs-3g/bitmap.h new file mode 100755 index 0000000..10b5f6c --- a/dev/null +++ b/include/ntfs-3g/bitmap.h @@ -0,0 +1,96 @@ +/* + * bitmap.h - Exports for bitmap handling. Originated from the Linux-NTFS project. + * + * Copyright (c) 2000-2004 Anton Altaparmakov + * Copyright (c) 2004-2005 Richard Russon + * + * This program/include file 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/include file 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 (in the main directory of the NTFS-3G + * distribution in the file COPYING); if not, write to the Free Software + * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _NTFS_BITMAP_H +#define _NTFS_BITMAP_H + +#include "types.h" +#include "attrib.h" + +/* + * NOTES: + * + * - Operations are 8-bit only to ensure the functions work both on little + * and big endian machines! So don't make them 32-bit ops! + * - bitmap starts at bit = 0 and ends at bit = bitmap size - 1. + * - _Caller_ has to make sure that the bit to operate on is less than the + * size of the bitmap. + */ + +extern void ntfs_bit_set(u8 *bitmap, const u64 bit, const u8 new_value); +extern char ntfs_bit_get(const u8 *bitmap, const u64 bit); +extern char ntfs_bit_get_and_set(u8 *bitmap, const u64 bit, const u8 new_value); +extern int ntfs_bitmap_set_run(ntfs_attr *na, s64 start_bit, s64 count); +extern int ntfs_bitmap_clear_run(ntfs_attr *na, s64 start_bit, s64 count); + +/** + * ntfs_bitmap_set_bit - set a bit in a bitmap + * @na: attribute containing the bitmap + * @bit: bit to set + * + * Set the @bit in the bitmap described by the attribute @na. + * + * On success return 0 and on error return -1 with errno set to the error code. + */ +static __inline__ int ntfs_bitmap_set_bit(ntfs_attr *na, s64 bit) +{ + return ntfs_bitmap_set_run(na, bit, 1); +} + +/** + * ntfs_bitmap_clear_bit - clear a bit in a bitmap + * @na: attribute containing the bitmap + * @bit: bit to clear + * + * Clear @bit in the bitmap described by the attribute @na. + * + * On success return 0 and on error return -1 with errno set to the error code. + */ +static __inline__ int ntfs_bitmap_clear_bit(ntfs_attr *na, s64 bit) +{ + return ntfs_bitmap_clear_run(na, bit, 1); +} + +/* + * rol32 - rotate a 32-bit value left + * + * @word: value to rotate + * @shift: bits to roll + */ +static __inline__ u32 ntfs_rol32(u32 word, unsigned int shift) +{ + return (word << shift) | (word >> (32 - shift)); +} + +/* + * ror32 - rotate a 32-bit value right + * + * @word: value to rotate + * @shift: bits to roll + */ +static __inline__ u32 ntfs_ror32(u32 word, unsigned int shift) +{ + return (word >> shift) | (word << (32 - shift)); +} + +#endif /* defined _NTFS_BITMAP_H */ + diff --git a/include/ntfs-3g/bootsect.h b/include/ntfs-3g/bootsect.h new file mode 100755 index 0000000..a299e82 --- a/dev/null +++ b/include/ntfs-3g/bootsect.h @@ -0,0 +1,42 @@ +/* + * bootsect.h - Exports for bootsector record handling. + * Originated from the Linux-NTFS project. + * + * Copyright (c) 2000-2002 Anton Altaparmakov + * Copyright (c) 2006 Szabolcs Szakacsits + * + * This program/include file 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/include file 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 (in the main directory of the NTFS-3G + * distribution in the file COPYING); if not, write to the Free Software + * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _NTFS_BOOTSECT_H +#define _NTFS_BOOTSECT_H + +#include "types.h" +#include "volume.h" +#include "layout.h" + +/** + * ntfs_boot_sector_is_ntfs - check a boot sector for describing an ntfs volume + * @b: buffer containing the boot sector + * + * This function checks the boot sector in @b for describing a valid ntfs + * volume. Return TRUE if @b is a valid NTFS boot sector or FALSE otherwise. + */ +extern BOOL ntfs_boot_sector_is_ntfs(NTFS_BOOT_SECTOR *b); +extern int ntfs_boot_sector_parse(ntfs_volume *vol, const NTFS_BOOT_SECTOR *bs); + +#endif /* defined _NTFS_BOOTSECT_H */ + diff --git a/include/ntfs-3g/cache.h b/include/ntfs-3g/cache.h new file mode 100755 index 0000000..67c3325 --- a/dev/null +++ b/include/ntfs-3g/cache.h @@ -0,0 +1,115 @@ +/* + * cache.h : deal with indexed LRU caches + * + * Copyright (c) 2008-2009 Jean-Pierre Andre + * + * This program/include file 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/include file 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 (in the main directory of the NTFS-3G + * distribution in the file COPYING); if not, write to the Free Software + * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _NTFS_CACHE_H_ +#define _NTFS_CACHE_H_ + +#include "volume.h" + +struct CACHED_GENERIC { + struct CACHED_GENERIC *next; + struct CACHED_GENERIC *previous; + void *variable; + size_t varsize; + void *fixed[0]; +} ; + +struct CACHED_INODE { + struct CACHED_INODE *next; + struct CACHED_INODE *previous; + const char *pathname; + size_t varsize; + /* above fields must match "struct CACHED_GENERIC" */ + u64 inum; +} ; + +struct CACHED_NIDATA { + struct CACHED_NIDATA *next; + struct CACHED_NIDATA *previous; + const char *pathname; /* not used */ + size_t varsize; /* not used */ + /* above fields must match "struct CACHED_GENERIC" */ + u64 inum; + ntfs_inode *ni; +} ; + +struct CACHED_LOOKUP { + struct CACHED_LOOKUP *next; + struct CACHED_LOOKUP *previous; + const char *name; + size_t namesize; + /* above fields must match "struct CACHED_GENERIC" */ + u64 parent; + u64 inum; +} ; + +enum { + CACHE_FREE = 1, + CACHE_NOHASH = 2 +} ; + +typedef int (*cache_compare)(const struct CACHED_GENERIC *cached, + const struct CACHED_GENERIC *item); +typedef void (*cache_free)(const struct CACHED_GENERIC *cached); +typedef int (*cache_hash)(const struct CACHED_GENERIC *cached); + +struct HASH_ENTRY { + struct HASH_ENTRY *next; + struct CACHED_GENERIC *entry; +} ; + +struct CACHE_HEADER { + const char *name; + struct CACHED_GENERIC *most_recent_entry; + struct CACHED_GENERIC *oldest_entry; + struct CACHED_GENERIC *free_entry; + struct HASH_ENTRY *free_hash; + struct HASH_ENTRY **first_hash; + cache_free dofree; + cache_hash dohash; + unsigned long reads; + unsigned long writes; + unsigned long hits; + int fixed_size; + int max_hash; + struct CACHED_GENERIC entry[0]; +} ; + + /* cast to generic, avoiding gcc warnings */ +#define GENERIC(pstr) ((const struct CACHED_GENERIC*)(const void*)(pstr)) + +struct CACHED_GENERIC *ntfs_fetch_cache(struct CACHE_HEADER *cache, + const struct CACHED_GENERIC *wanted, + cache_compare compare); +struct CACHED_GENERIC *ntfs_enter_cache(struct CACHE_HEADER *cache, + const struct CACHED_GENERIC *item, + cache_compare compare); +int ntfs_invalidate_cache(struct CACHE_HEADER *cache, + const struct CACHED_GENERIC *item, + cache_compare compare, int flags); +int ntfs_remove_cache(struct CACHE_HEADER *cache, + struct CACHED_GENERIC *item, int flags); + +void ntfs_create_lru_caches(ntfs_volume *vol); +void ntfs_free_lru_caches(ntfs_volume *vol); + +#endif /* _NTFS_CACHE_H_ */ + diff --git a/include/ntfs-3g/collate.h b/include/ntfs-3g/collate.h new file mode 100755 index 0000000..fe38383 --- a/dev/null +++ b/include/ntfs-3g/collate.h @@ -0,0 +1,34 @@ +/* + * collate.h - Defines for NTFS collation handling. Originated from the Linux-NTFS + * project. + * + * Copyright (c) 2004 Anton Altaparmakov + * Copyright (c) 2005 Yura Pakhuchiy + * + * This program/include file 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/include file 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 (in the main directory of the NTFS-3G + * distribution in the file COPYING); if not, write to the Free Software + * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _NTFS_COLLATE_H +#define _NTFS_COLLATE_H + +#include "types.h" +#include "volume.h" + +#define NTFS_COLLATION_ERROR -2 + +extern COLLATE ntfs_get_collate_function(COLLATION_RULES); + +#endif /* _NTFS_COLLATE_H */ diff --git a/include/ntfs-3g/compat.h b/include/ntfs-3g/compat.h new file mode 100755 index 0000000..d662059 --- a/dev/null +++ b/include/ntfs-3g/compat.h @@ -0,0 +1,69 @@ +/* + * compat.h - Tweaks for Windows compatibility. + * + * Copyright (c) 2002 Richard Russon + * Copyright (c) 2002-2004 Anton Altaparmakov + * Copyright (c) 2008-2009 Szabolcs Szakacsits + * + * This program/include file 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/include file 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 (in the main directory of the NTFS-3G + * distribution in the file COPYING); if not, write to the Free Software + * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _NTFS_COMPAT_H +#define _NTFS_COMPAT_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#ifdef HAVE_SYS_PARAM_H +#include +#endif + +#ifndef PATH_MAX +#define PATH_MAX 4096 +#endif + +#ifndef HAVE_FFS +extern int ffs(int i); +#endif /* HAVE_FFS */ + +#ifndef HAVE_DAEMON +extern int daemon(int nochdir, int noclose); +#endif /* HAVE_DAEMON */ + +#ifndef HAVE_STRSEP +extern char *strsep(char **stringp, const char *delim); +#endif /* HAVE_STRSEP */ + +#ifdef WINDOWS + +#define HAVE_STDIO_H /* mimic config.h */ +#define HAVE_STDARG_H + +#define atoll _atoi64 +#define fdatasync commit +#define __inline__ inline +#define __attribute__(X) /*nothing*/ + +#else /* !defined WINDOWS */ + +#ifndef O_BINARY +#define O_BINARY 0 /* unix is binary by default */ +#endif + +#endif /* defined WINDOWS */ + +#endif /* defined _NTFS_COMPAT_H */ + diff --git a/include/ntfs-3g/compress.h b/include/ntfs-3g/compress.h new file mode 100755 index 0000000..809c3c9 --- a/dev/null +++ b/include/ntfs-3g/compress.h @@ -0,0 +1,39 @@ +/* + * compress.h - Exports for compressed attribute handling. + * Originated from the Linux-NTFS project. + * + * Copyright (c) 2004 Anton Altaparmakov + * + * This program/include file 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/include file 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 (in the main directory of the NTFS-3G + * distribution in the file COPYING); if not, write to the Free Software + * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _NTFS_COMPRESS_H +#define _NTFS_COMPRESS_H + +#include "types.h" +#include "attrib.h" + +extern s64 ntfs_compressed_attr_pread(ntfs_attr *na, s64 pos, s64 count, + void *b); + +extern s64 ntfs_compressed_pwrite(ntfs_attr *na, runlist_element *brl, s64 wpos, + s64 offs, s64 to_write, s64 rounded, + const void *b, int compressed_part); + +extern int ntfs_compressed_close(ntfs_attr *na, runlist_element *brl, s64 offs); + +#endif /* defined _NTFS_COMPRESS_H */ + diff --git a/include/ntfs-3g/debug.h b/include/ntfs-3g/debug.h new file mode 100755 index 0000000..cf39b62 --- a/dev/null +++ b/include/ntfs-3g/debug.h @@ -0,0 +1,47 @@ +/* + * debug.h - Debugging output functions. Originated from the Linux-NTFS project. + * + * Copyright (c) 2002-2004 Anton Altaparmakov + * + * This program/include file 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/include file 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 (in the main directory of the NTFS-3G + * distribution in the file COPYING); if not, write to the Free Software + * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _NTFS_DEBUG_H +#define _NTFS_DEBUG_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "logging.h" + +struct _runlist_element; + +#ifdef DEBUG +extern void ntfs_debug_runlist_dump(const struct _runlist_element *rl); +#else +static __inline__ void ntfs_debug_runlist_dump(const struct _runlist_element *rl __attribute__((unused))) {} +#endif + +#define NTFS_BUG(msg) \ +{ \ + int ___i; \ + ntfs_log_critical("Bug in %s(): %s\n", __FUNCTION__, msg); \ + ntfs_log_debug("Forcing segmentation fault!"); \ + ___i = ((int*)NULL)[1]; \ +} + +#endif /* defined _NTFS_DEBUG_H */ diff --git a/include/ntfs-3g/device.h b/include/ntfs-3g/device.h new file mode 100755 index 0000000..a19d29c --- a/dev/null +++ b/include/ntfs-3g/device.h @@ -0,0 +1,128 @@ +/* + * device.h - Exports for low level device io. Originated from the Linux-NTFS project. + * + * Copyright (c) 2000-2006 Anton Altaparmakov + * + * This program/include file 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/include file 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 (in the main directory of the NTFS-3G + * distribution in the file COPYING); if not, write to the Free Software + * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _NTFS_DEVICE_H +#define _NTFS_DEVICE_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "device_io.h" +#include "types.h" +#include "support.h" +#include "volume.h" + +/** + * enum ntfs_device_state_bits - + * + * Defined bits for the state field in the ntfs_device structure. + */ +typedef enum { + ND_Open, /* 1: Device is open. */ + ND_ReadOnly, /* 1: Device is read-only. */ + ND_Dirty, /* 1: Device is dirty, needs sync. */ + ND_Block, /* 1: Device is a block device. */ +} ntfs_device_state_bits; + +#define test_ndev_flag(nd, flag) test_bit(ND_##flag, (nd)->d_state) +#define set_ndev_flag(nd, flag) set_bit(ND_##flag, (nd)->d_state) +#define clear_ndev_flag(nd, flag) clear_bit(ND_##flag, (nd)->d_state) + +#define NDevOpen(nd) test_ndev_flag(nd, Open) +#define NDevSetOpen(nd) set_ndev_flag(nd, Open) +#define NDevClearOpen(nd) clear_ndev_flag(nd, Open) + +#define NDevReadOnly(nd) test_ndev_flag(nd, ReadOnly) +#define NDevSetReadOnly(nd) set_ndev_flag(nd, ReadOnly) +#define NDevClearReadOnly(nd) clear_ndev_flag(nd, ReadOnly) + +#define NDevDirty(nd) test_ndev_flag(nd, Dirty) +#define NDevSetDirty(nd) set_ndev_flag(nd, Dirty) +#define NDevClearDirty(nd) clear_ndev_flag(nd, Dirty) + +#define NDevBlock(nd) test_ndev_flag(nd, Block) +#define NDevSetBlock(nd) set_ndev_flag(nd, Block) +#define NDevClearBlock(nd) clear_ndev_flag(nd, Block) + +/** + * struct ntfs_device - + * + * The ntfs device structure defining all operations needed to access the low + * level device underlying the ntfs volume. + */ +struct ntfs_device { + struct ntfs_device_operations *d_ops; /* Device operations. */ + unsigned long d_state; /* State of the device. */ + char *d_name; /* Name of device. */ + void *d_private; /* Private data used by the + device operations. */ +}; + +struct stat; + +/** + * struct ntfs_device_operations - + * + * The ntfs device operations defining all operations that can be performed on + * the low level device described by an ntfs device structure. + */ +struct ntfs_device_operations { + int (*open)(struct ntfs_device *dev, int flags); + int (*close)(struct ntfs_device *dev); + s64 (*seek)(struct ntfs_device *dev, s64 offset, int whence); + s64 (*read)(struct ntfs_device *dev, void *buf, s64 count); + s64 (*write)(struct ntfs_device *dev, const void *buf, s64 count); + s64 (*pread)(struct ntfs_device *dev, void *buf, s64 count, s64 offset); + s64 (*pwrite)(struct ntfs_device *dev, const void *buf, s64 count, + s64 offset); + int (*sync)(struct ntfs_device *dev); + int (*stat)(struct ntfs_device *dev, struct stat *buf); + int (*ioctl)(struct ntfs_device *dev, int request, void *argp); +}; + +extern struct ntfs_device *ntfs_device_alloc(const char *name, const long state, + struct ntfs_device_operations *dops, void *priv_data); +extern int ntfs_device_free(struct ntfs_device *dev); + +extern s64 ntfs_pread(struct ntfs_device *dev, const s64 pos, s64 count, + void *b); +extern s64 ntfs_pwrite(struct ntfs_device *dev, const s64 pos, s64 count, + const void *b); + +extern s64 ntfs_mst_pread(struct ntfs_device *dev, const s64 pos, s64 count, + const u32 bksize, void *b); +extern s64 ntfs_mst_pwrite(struct ntfs_device *dev, const s64 pos, s64 count, + const u32 bksize, void *b); + +extern s64 ntfs_cluster_read(const ntfs_volume *vol, const s64 lcn, + const s64 count, void *b); +extern s64 ntfs_cluster_write(const ntfs_volume *vol, const s64 lcn, + const s64 count, const void *b); + +extern s64 ntfs_device_size_get(struct ntfs_device *dev, int block_size); +extern s64 ntfs_device_partition_start_sector_get(struct ntfs_device *dev); +extern int ntfs_device_heads_get(struct ntfs_device *dev); +extern int ntfs_device_sectors_per_track_get(struct ntfs_device *dev); +extern int ntfs_device_sector_size_get(struct ntfs_device *dev); +extern int ntfs_device_block_size_set(struct ntfs_device *dev, int block_size); + +#endif /* defined _NTFS_DEVICE_H */ diff --git a/include/ntfs-3g/device_io.h b/include/ntfs-3g/device_io.h new file mode 100755 index 0000000..8437cc2 --- a/dev/null +++ b/include/ntfs-3g/device_io.h @@ -0,0 +1,77 @@ +/* + * device_io.h - Exports for default device io. Originated from the Linux-NTFS project. + * + * Copyright (c) 2000-2006 Anton Altaparmakov + * + * This program/include file 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/include file 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 (in the main directory of the NTFS-3G + * distribution in the file COPYING); if not, write to the Free Software + * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _NTFS_DEVICE_IO_H +#define _NTFS_DEVICE_IO_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifndef NO_NTFS_DEVICE_DEFAULT_IO_OPS + +#ifndef __CYGWIN32__ + +/* Not on Cygwin; use standard Unix style low level device operations. */ +#define ntfs_device_default_io_ops ntfs_device_unix_io_ops + +#else /* __CYGWIN32__ */ + +#ifndef HDIO_GETGEO +# define HDIO_GETGEO 0x301 +/** + * struct hd_geometry - + */ +struct hd_geometry { + unsigned char heads; + unsigned char sectors; + unsigned short cylinders; + unsigned long start; +}; +#endif +#ifndef BLKGETSIZE +# define BLKGETSIZE 0x1260 +#endif +#ifndef BLKSSZGET +# define BLKSSZGET 0x1268 +#endif +#ifndef BLKGETSIZE64 +# define BLKGETSIZE64 0x80041272 +#endif +#ifndef BLKBSZSET +# define BLKBSZSET 0x40041271 +#endif + +/* On Cygwin; use Win32 low level device operations. */ +#define ntfs_device_default_io_ops ntfs_device_win32_io_ops + +#endif /* __CYGWIN32__ */ + + +/* Forward declaration. */ +struct ntfs_device_operations; + +extern struct ntfs_device_operations ntfs_device_default_io_ops; + +#endif /* NO_NTFS_DEVICE_DEFAULT_IO_OPS */ + +#endif /* defined _NTFS_DEVICE_IO_H */ + diff --git a/include/ntfs-3g/dir.h b/include/ntfs-3g/dir.h new file mode 100755 index 0000000..56e76fe --- a/dev/null +++ b/include/ntfs-3g/dir.h @@ -0,0 +1,128 @@ +/* + * dir.h - Exports for directory handling. Originated from the Linux-NTFS project. + * + * Copyright (c) 2002 Anton Altaparmakov + * Copyright (c) 2005-2006 Yura Pakhuchiy + * Copyright (c) 2004-2005 Richard Russon + * Copyright (c) 2005-2008 Szabolcs Szakacsits + * + * This program/include file 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/include file 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 (in the main directory of the NTFS-3G + * distribution in the file COPYING); if not, write to the Free Software + * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _NTFS_DIR_H +#define _NTFS_DIR_H + +#include "types.h" + +#define PATH_SEP '/' + +/* + * We do not have these under DJGPP, so define our version that do not conflict + * with other S_IFs defined under DJGPP. + */ +#ifdef DJGPP +#ifndef S_IFLNK +#define S_IFLNK 0120000 +#endif +#ifndef S_ISLNK +#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) +#endif +#ifndef S_IFSOCK +#define S_IFSOCK 0140000 +#endif +#ifndef S_ISSOCK +#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK) +#endif +#endif + +/* + * The little endian Unicode strings $I30, $SII, $SDH, $O, $Q, $R + * as a global constant. + */ +extern ntfschar NTFS_INDEX_I30[5]; +extern ntfschar NTFS_INDEX_SII[5]; +extern ntfschar NTFS_INDEX_SDH[5]; +extern ntfschar NTFS_INDEX_O[3]; +extern ntfschar NTFS_INDEX_Q[3]; +extern ntfschar NTFS_INDEX_R[3]; + +extern u64 ntfs_inode_lookup_by_name(ntfs_inode *dir_ni, + const ntfschar *uname, const int uname_len); +extern u64 ntfs_inode_lookup_by_mbsname(ntfs_inode *dir_ni, const char *name); +extern void ntfs_inode_update_mbsname(ntfs_inode *dir_ni, const char *name, + u64 inum); + +extern ntfs_inode *ntfs_pathname_to_inode(ntfs_volume *vol, ntfs_inode *parent, + const char *pathname); +extern ntfs_inode *ntfs_create(ntfs_inode *dir_ni, le32 securid, + ntfschar *name, u8 name_len, mode_t type); +extern ntfs_inode *ntfs_create_device(ntfs_inode *dir_ni, le32 securid, + ntfschar *name, u8 name_len, mode_t type, dev_t dev); +extern ntfs_inode *ntfs_create_symlink(ntfs_inode *dir_ni, le32 securid, + ntfschar *name, u8 name_len, ntfschar *target, int target_len); +extern int ntfs_check_empty_dir(ntfs_inode *ni); +extern int ntfs_delete(ntfs_volume *vol, const char *path, + ntfs_inode *ni, ntfs_inode *dir_ni, ntfschar *name, + u8 name_len); + +extern int ntfs_link(ntfs_inode *ni, ntfs_inode *dir_ni, ntfschar *name, + u8 name_len); + +/* + * File types (adapted from include ) + */ +#define NTFS_DT_UNKNOWN 0 +#define NTFS_DT_FIFO 1 +#define NTFS_DT_CHR 2 +#define NTFS_DT_DIR 4 +#define NTFS_DT_BLK 6 +#define NTFS_DT_REG 8 +#define NTFS_DT_LNK 10 +#define NTFS_DT_SOCK 12 +#define NTFS_DT_WHT 14 + +/* + * This is the "ntfs_filldir" function type, used by ntfs_readdir() to let + * the caller specify what kind of dirent layout it wants to have. + * This allows the caller to read directories into their application or + * to have different dirent layouts depending on the binary type. + */ +typedef int (*ntfs_filldir_t)(void *dirent, const ntfschar *name, + const int name_len, const int name_type, const s64 pos, + const MFT_REF mref, const unsigned dt_type); + +extern int ntfs_readdir(ntfs_inode *dir_ni, s64 *pos, + void *dirent, ntfs_filldir_t filldir); + +ntfs_inode *ntfs_dir_parent_inode(ntfs_inode *ni); + +int ntfs_get_ntfs_dos_name(ntfs_inode *ni, ntfs_inode *dir_ni, + char *value, size_t size); +int ntfs_set_ntfs_dos_name(ntfs_inode *ni, ntfs_inode *dir_ni, + const char *value, size_t size, int flags); +int ntfs_remove_ntfs_dos_name(ntfs_inode *ni, ntfs_inode *dir_ni); + +#if CACHE_INODE_SIZE + +struct CACHED_GENERIC; + +extern int ntfs_dir_inode_hash(const struct CACHED_GENERIC *cached); +extern int ntfs_dir_lookup_hash(const struct CACHED_GENERIC *cached); + +#endif + +#endif /* defined _NTFS_DIR_H */ + diff --git a/include/ntfs-3g/efs.h b/include/ntfs-3g/efs.h new file mode 100755 index 0000000..6eada06 --- a/dev/null +++ b/include/ntfs-3g/efs.h @@ -0,0 +1,30 @@ +/* + * + * Copyright (c) 2009 Martin Bene + * + * This program/include file 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/include file 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 (in the main directory of the NTFS-3G + * distribution in the file COPYING); if not, write to the Free Software + * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef EFS_H +#define EFS_H + +int ntfs_get_efs_info(ntfs_inode *ni, char *value, size_t size); + +int ntfs_set_efs_info(ntfs_inode *ni, + const char *value, size_t size, int flags); +int ntfs_efs_fixup_attribute(ntfs_attr_search_ctx *ctx, ntfs_attr *na); + +#endif /* EFS_H */ diff --git a/include/ntfs-3g/endians.h b/include/ntfs-3g/endians.h new file mode 100755 index 0000000..397f1c2 --- a/dev/null +++ b/include/ntfs-3g/endians.h @@ -0,0 +1,203 @@ +/* + * endians.h - Definitions related to handling of byte ordering. + * Originated from the Linux-NTFS project. + * + * Copyright (c) 2000-2005 Anton Altaparmakov + * + * This program/include file 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/include file 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 (in the main directory of the NTFS-3G + * distribution in the file COPYING); if not, write to the Free Software + * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _NTFS_ENDIANS_H +#define _NTFS_ENDIANS_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/* + * Notes: + * We define the conversion functions including typecasts since the + * defaults don't necessarily perform appropriate typecasts. + * Also, using our own functions means that we can change them if it + * turns out that we do need to use the unaligned access macros on + * architectures requiring aligned memory accesses... + */ + +#ifdef HAVE_ENDIAN_H +#include +#endif +#ifdef HAVE_SYS_ENDIAN_H +#include +#endif +#ifdef HAVE_MACHINE_ENDIAN_H +#include +#endif +#ifdef HAVE_SYS_BYTEORDER_H +#include +#endif +#ifdef HAVE_SYS_PARAM_H +#include +#endif + +#ifndef __BYTE_ORDER +# if defined(_BYTE_ORDER) +# define __BYTE_ORDER _BYTE_ORDER +# define __LITTLE_ENDIAN _LITTLE_ENDIAN +# define __BIG_ENDIAN _BIG_ENDIAN +# elif defined(BYTE_ORDER) +# define __BYTE_ORDER BYTE_ORDER +# define __LITTLE_ENDIAN LITTLE_ENDIAN +# define __BIG_ENDIAN BIG_ENDIAN +# elif defined(__BYTE_ORDER__) +# define __BYTE_ORDER __BYTE_ORDER__ +# define __LITTLE_ENDIAN __LITTLE_ENDIAN__ +# define __BIG_ENDIAN __BIG_ENDIAN__ +# elif (defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN)) || \ + defined(WORDS_LITTLEENDIAN) +# define __BYTE_ORDER 1 +# define __LITTLE_ENDIAN 1 +# define __BIG_ENDIAN 0 +# elif (!defined(_LITTLE_ENDIAN) && defined(_BIG_ENDIAN)) || \ + defined(WORDS_BIGENDIAN) +# define __BYTE_ORDER 0 +# define __LITTLE_ENDIAN 1 +# define __BIG_ENDIAN 0 +# else +# error "__BYTE_ORDER is not defined." +# endif +#endif + +#define __ntfs_bswap_constant_16(x) \ + (u16)((((u16)(x) & 0xff00) >> 8) | \ + (((u16)(x) & 0x00ff) << 8)) + +#define __ntfs_bswap_constant_32(x) \ + (u32)((((u32)(x) & 0xff000000u) >> 24) | \ + (((u32)(x) & 0x00ff0000u) >> 8) | \ + (((u32)(x) & 0x0000ff00u) << 8) | \ + (((u32)(x) & 0x000000ffu) << 24)) + +#define __ntfs_bswap_constant_64(x) \ + (u64)((((u64)(x) & 0xff00000000000000ull) >> 56) | \ + (((u64)(x) & 0x00ff000000000000ull) >> 40) | \ + (((u64)(x) & 0x0000ff0000000000ull) >> 24) | \ + (((u64)(x) & 0x000000ff00000000ull) >> 8) | \ + (((u64)(x) & 0x00000000ff000000ull) << 8) | \ + (((u64)(x) & 0x0000000000ff0000ull) << 24) | \ + (((u64)(x) & 0x000000000000ff00ull) << 40) | \ + (((u64)(x) & 0x00000000000000ffull) << 56)) + +#ifdef HAVE_BYTESWAP_H +# include +#else +# define bswap_16(x) __ntfs_bswap_constant_16(x) +# define bswap_32(x) __ntfs_bswap_constant_32(x) +# define bswap_64(x) __ntfs_bswap_constant_64(x) +#endif + +#if defined(__LITTLE_ENDIAN) && (__BYTE_ORDER == __LITTLE_ENDIAN) + +#define __le16_to_cpu(x) (x) +#define __le32_to_cpu(x) (x) +#define __le64_to_cpu(x) (x) + +#define __cpu_to_le16(x) (x) +#define __cpu_to_le32(x) (x) +#define __cpu_to_le64(x) (x) + +#define __constant_le16_to_cpu(x) (x) +#define __constant_le32_to_cpu(x) (x) +#define __constant_le64_to_cpu(x) (x) + +#define __constant_cpu_to_le16(x) (x) +#define __constant_cpu_to_le32(x) (x) +#define __constant_cpu_to_le64(x) (x) + +#elif defined(__BIG_ENDIAN) && (__BYTE_ORDER == __BIG_ENDIAN) + +#define __le16_to_cpu(x) bswap_16(x) +#define __le32_to_cpu(x) bswap_32(x) +#define __le64_to_cpu(x) bswap_64(x) + +#define __cpu_to_le16(x) bswap_16(x) +#define __cpu_to_le32(x) bswap_32(x) +#define __cpu_to_le64(x) bswap_64(x) + +#define __constant_le16_to_cpu(x) __ntfs_bswap_constant_16((u16)(x)) +#define __constant_le32_to_cpu(x) __ntfs_bswap_constant_32((u32)(x)) +#define __constant_le64_to_cpu(x) __ntfs_bswap_constant_64((u64)(x)) + +#define __constant_cpu_to_le16(x) __ntfs_bswap_constant_16((u16)(x)) +#define __constant_cpu_to_le32(x) __ntfs_bswap_constant_32((u32)(x)) +#define __constant_cpu_to_le64(x) __ntfs_bswap_constant_64((u64)(x)) + +#else + +#error "You must define __BYTE_ORDER to be __LITTLE_ENDIAN or __BIG_ENDIAN." + +#endif + +/* Unsigned from LE to CPU conversion. */ + +#define le16_to_cpu(x) (u16)__le16_to_cpu((u16)(x)) +#define le32_to_cpu(x) (u32)__le32_to_cpu((u32)(x)) +#define le64_to_cpu(x) (u64)__le64_to_cpu((u64)(x)) + +#define le16_to_cpup(x) (u16)__le16_to_cpu(*(const u16*)(x)) +#define le32_to_cpup(x) (u32)__le32_to_cpu(*(const u32*)(x)) +#define le64_to_cpup(x) (u64)__le64_to_cpu(*(const u64*)(x)) + +/* Signed from LE to CPU conversion. */ + +#define sle16_to_cpu(x) (s16)__le16_to_cpu((s16)(x)) +#define sle32_to_cpu(x) (s32)__le32_to_cpu((s32)(x)) +#define sle64_to_cpu(x) (s64)__le64_to_cpu((s64)(x)) + +#define sle16_to_cpup(x) (s16)__le16_to_cpu(*(s16*)(x)) +#define sle32_to_cpup(x) (s32)__le32_to_cpu(*(s32*)(x)) +#define sle64_to_cpup(x) (s64)__le64_to_cpu(*(s64*)(x)) + +/* Unsigned from CPU to LE conversion. */ + +#define cpu_to_le16(x) (u16)__cpu_to_le16((u16)(x)) +#define cpu_to_le32(x) (u32)__cpu_to_le32((u32)(x)) +#define cpu_to_le64(x) (u64)__cpu_to_le64((u64)(x)) + +#define cpu_to_le16p(x) (u16)__cpu_to_le16(*(u16*)(x)) +#define cpu_to_le32p(x) (u32)__cpu_to_le32(*(u32*)(x)) +#define cpu_to_le64p(x) (u64)__cpu_to_le64(*(u64*)(x)) + +/* Signed from CPU to LE conversion. */ + +#define cpu_to_sle16(x) (s16)__cpu_to_le16((s16)(x)) +#define cpu_to_sle32(x) (s32)__cpu_to_le32((s32)(x)) +#define cpu_to_sle64(x) (s64)__cpu_to_le64((s64)(x)) + +#define cpu_to_sle16p(x) (s16)__cpu_to_le16(*(s16*)(x)) +#define cpu_to_sle32p(x) (s32)__cpu_to_le32(*(s32*)(x)) +#define cpu_to_sle64p(x) (s64)__cpu_to_le64(*(s64*)(x)) + +/* Constant endianness conversion defines. */ + +#define const_le16_to_cpu(x) __constant_le16_to_cpu(x) +#define const_le32_to_cpu(x) __constant_le32_to_cpu(x) +#define const_le64_to_cpu(x) __constant_le64_to_cpu(x) + +#define const_cpu_to_le16(x) __constant_cpu_to_le16(x) +#define const_cpu_to_le32(x) __constant_cpu_to_le32(x) +#define const_cpu_to_le64(x) __constant_cpu_to_le64(x) + +#endif /* defined _NTFS_ENDIANS_H */ diff --git a/include/ntfs-3g/index.h b/include/ntfs-3g/index.h new file mode 100755 index 0000000..c0e7618 --- a/dev/null +++ b/include/ntfs-3g/index.h @@ -0,0 +1,167 @@ +/* + * index.h - Defines for NTFS index handling. Originated from the Linux-NTFS project. + * + * Copyright (c) 2004 Anton Altaparmakov + * Copyright (c) 2004-2005 Richard Russon + * Copyright (c) 2005 Yura Pakhuchiy + * Copyright (c) 2006-2008 Szabolcs Szakacsits + * + * This program/include file 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/include file 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 (in the main directory of the NTFS-3G + * distribution in the file COPYING); if not, write to the Free Software + * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _NTFS_INDEX_H +#define _NTFS_INDEX_H + +/* Convenience macros to test the versions of gcc. + * Use them like this: + * #if __GNUC_PREREQ (2,8) + * ... code requiring gcc 2.8 or later ... + * #endif + * Note - they won't work for gcc1 or glibc1, since the _MINOR macros + * were not defined then. + */ + +#ifndef __GNUC_PREREQ +# if defined __GNUC__ && defined __GNUC_MINOR__ +# define __GNUC_PREREQ(maj, min) \ + ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min)) +# else +# define __GNUC_PREREQ(maj, min) 0 +# endif +#endif + +/* allows us to warn about unused results of certain function calls */ +#ifndef __attribute_warn_unused_result__ +# if __GNUC_PREREQ (3,4) +# define __attribute_warn_unused_result__ \ + __attribute__ ((__warn_unused_result__)) +# else +# define __attribute_warn_unused_result__ /* empty */ +# endif +#endif + +#include "attrib.h" +#include "types.h" +#include "layout.h" +#include "inode.h" +#include "mft.h" + +#define VCN_INDEX_ROOT_PARENT ((VCN)-2) + +#define MAX_PARENT_VCN 32 + +typedef int (*COLLATE)(ntfs_volume *vol, const void *data1, int len1, + const void *data2, int len2); + +/** + * struct ntfs_index_context - + * @ni: inode containing the @entry described by this context + * @name: name of the index described by this context + * @name_len: length of the index name + * @entry: index entry (points into @ir or @ia) + * @data: index entry data (points into @entry) + * @data_len: length in bytes of @data + * @is_in_root: TRUE if @entry is in @ir or FALSE if it is in @ia + * @ir: index root if @is_in_root or NULL otherwise + * @actx: attribute search context if in root or NULL otherwise + * @ia: index block if @is_in_root is FALSE or NULL otherwise + * @ia_na: opened INDEX_ALLOCATION attribute + * @parent_pos: parent entries' positions in the index block + * @parent_vcn: entry's parent node or VCN_INDEX_ROOT_PARENT + * @new_vcn: new VCN if we need to create a new index block + * @median: move to the parent if splitting index blocks + * @ib_dirty: TRUE if index block was changed + * @block_size: index block size + * @vcn_size_bits: VCN size bits for this index block + * + * @ni is the inode this context belongs to. + * + * @entry is the index entry described by this context. @data and @data_len + * are the index entry data and its length in bytes, respectively. @data + * simply points into @entry. This is probably what the user is interested in. + * + * If @is_in_root is TRUE, @entry is in the index root attribute @ir described + * by the attribute search context @actx and inode @ni. @ia and + * @ib_dirty are undefined in this case. + * + * If @is_in_root is FALSE, @entry is in the index allocation attribute and @ia + * point to the index allocation block and VCN where it's placed, + * respectively. @ir and @actx are NULL in this case. @ia_na is opened + * INDEX_ALLOCATION attribute. @ib_dirty is TRUE if index block was changed and + * FALSE otherwise. + * + * To obtain a context call ntfs_index_ctx_get(). + * + * When finished with the @entry and its @data, call ntfs_index_ctx_put() to + * free the context and other associated resources. + * + * If the index entry was modified, call ntfs_index_entry_mark_dirty() before + * the call to ntfs_index_ctx_put() to ensure that the changes are written + * to disk. + */ +typedef struct { + ntfs_inode *ni; + ntfschar *name; + u32 name_len; + INDEX_ENTRY *entry; + void *data; + u16 data_len; + COLLATE collate; + BOOL is_in_root; + INDEX_ROOT *ir; + ntfs_attr_search_ctx *actx; + INDEX_BLOCK *ib; + ntfs_attr *ia_na; + int parent_pos[MAX_PARENT_VCN]; /* parent entries' positions */ + VCN parent_vcn[MAX_PARENT_VCN]; /* entry's parent nodes */ + int pindex; /* maximum it's the number of the parent nodes */ + BOOL ib_dirty; + u32 block_size; + u8 vcn_size_bits; +} ntfs_index_context; + +extern ntfs_index_context *ntfs_index_ctx_get(ntfs_inode *ni, + ntfschar *name, u32 name_len); +extern void ntfs_index_ctx_put(ntfs_index_context *ictx); +extern void ntfs_index_ctx_reinit(ntfs_index_context *ictx); + +extern int ntfs_index_lookup(const void *key, const int key_len, + ntfs_index_context *ictx) __attribute_warn_unused_result__; + +extern INDEX_ENTRY *ntfs_index_next(INDEX_ENTRY *ie, + ntfs_index_context *ictx); + +extern int ntfs_index_add_filename(ntfs_inode *ni, FILE_NAME_ATTR *fn, + MFT_REF mref); +extern int ntfs_index_remove(ntfs_inode *dir_ni, ntfs_inode *ni, + const void *key, const int keylen); + +extern INDEX_ROOT *ntfs_index_root_get(ntfs_inode *ni, ATTR_RECORD *attr); + +extern VCN ntfs_ie_get_vcn(INDEX_ENTRY *ie); + +extern void ntfs_index_entry_mark_dirty(ntfs_index_context *ictx); + +extern char *ntfs_ie_filename_get(INDEX_ENTRY *ie); +extern void ntfs_ie_filename_dump(INDEX_ENTRY *ie); +extern void ntfs_ih_filename_dump(INDEX_HEADER *ih); + +/* the following was added by JPA for use in security.c */ +extern int ntfs_ie_add(ntfs_index_context *icx, INDEX_ENTRY *ie); +extern int ntfs_index_rm(ntfs_index_context *icx); + +#endif /* _NTFS_INDEX_H */ + diff --git a/include/ntfs-3g/inode.h b/include/ntfs-3g/inode.h new file mode 100755 index 0000000..5a6f7da --- a/dev/null +++ b/include/ntfs-3g/inode.h @@ -0,0 +1,225 @@ +/* + * inode.h - Defines for NTFS inode handling. Originated from the Linux-NTFS project. + * + * Copyright (c) 2001-2004 Anton Altaparmakov + * Copyright (c) 2004-2007 Yura Pakhuchiy + * Copyright (c) 2004-2005 Richard Russon + * Copyright (c) 2006-2008 Szabolcs Szakacsits + * + * This program/include file 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/include file 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 (in the main directory of the NTFS-3G + * distribution in the file COPYING); if not, write to the Free Software + * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _NTFS_INODE_H +#define _NTFS_INODE_H + +/* Forward declaration */ +typedef struct _ntfs_inode ntfs_inode; + +#include "types.h" +#include "layout.h" +#include "support.h" +#include "volume.h" +#include "ntfstime.h" + +/** + * enum ntfs_inode_state_bits - + * + * Defined bits for the state field in the ntfs_inode structure. + * (f) = files only, (d) = directories only + */ +typedef enum { + NI_Dirty, /* 1: Mft record needs to be written to disk. */ + + /* The NI_AttrList* tests only make sense for base inodes. */ + NI_AttrList, /* 1: Mft record contains an attribute list. */ + NI_AttrListDirty, /* 1: Attribute list needs to be written to the + mft record and then to disk. */ + NI_FileNameDirty, /* 1: FILE_NAME attributes need to be updated + in the index. */ + NI_v3_Extensions, /* 1: JPA v3.x extensions present. */ + NI_TimesSet, /* 1: Use times which were set */ + NI_KnownSize, /* 1: Set if sizes are meaningful */ +} ntfs_inode_state_bits; + +#define test_nino_flag(ni, flag) test_bit(NI_##flag, (ni)->state) +#define set_nino_flag(ni, flag) set_bit(NI_##flag, (ni)->state) +#define clear_nino_flag(ni, flag) clear_bit(NI_##flag, (ni)->state) + +#define test_and_set_nino_flag(ni, flag) \ + test_and_set_bit(NI_##flag, (ni)->state) +#define test_and_clear_nino_flag(ni, flag) \ + test_and_clear_bit(NI_##flag, (ni)->state) + +#define NInoDirty(ni) test_nino_flag(ni, Dirty) +#define NInoSetDirty(ni) set_nino_flag(ni, Dirty) +#define NInoClearDirty(ni) clear_nino_flag(ni, Dirty) +#define NInoTestAndSetDirty(ni) test_and_set_nino_flag(ni, Dirty) +#define NInoTestAndClearDirty(ni) test_and_clear_nino_flag(ni, Dirty) + +#define NInoAttrList(ni) test_nino_flag(ni, AttrList) +#define NInoSetAttrList(ni) set_nino_flag(ni, AttrList) +#define NInoClearAttrList(ni) clear_nino_flag(ni, AttrList) + + +#define test_nino_al_flag(ni, flag) test_nino_flag(ni, AttrList##flag) +#define set_nino_al_flag(ni, flag) set_nino_flag(ni, AttrList##flag) +#define clear_nino_al_flag(ni, flag) clear_nino_flag(ni, AttrList##flag) + +#define test_and_set_nino_al_flag(ni, flag) \ + test_and_set_nino_flag(ni, AttrList##flag) +#define test_and_clear_nino_al_flag(ni, flag) \ + test_and_clear_nino_flag(ni, AttrList##flag) + +#define NInoAttrListDirty(ni) test_nino_al_flag(ni, Dirty) +#define NInoAttrListSetDirty(ni) set_nino_al_flag(ni, Dirty) +#define NInoAttrListClearDirty(ni) clear_nino_al_flag(ni, Dirty) +#define NInoAttrListTestAndSetDirty(ni) test_and_set_nino_al_flag(ni, Dirty) +#define NInoAttrListTestAndClearDirty(ni) test_and_clear_nino_al_flag(ni, Dirty) + +#define NInoFileNameDirty(ni) test_nino_flag(ni, FileNameDirty) +#define NInoFileNameSetDirty(ni) set_nino_flag(ni, FileNameDirty) +#define NInoFileNameClearDirty(ni) clear_nino_flag(ni, FileNameDirty) +#define NInoFileNameTestAndSetDirty(ni) \ + test_and_set_nino_flag(ni, FileNameDirty) +#define NInoFileNameTestAndClearDirty(ni) \ + test_and_clear_nino_flag(ni, FileNameDirty) + +/** + * struct _ntfs_inode - The NTFS in-memory inode structure. + * + * It is just used as an extension to the fields already provided in the VFS + * inode. + */ +struct _ntfs_inode { + u64 mft_no; /* Inode / mft record number. */ + MFT_RECORD *mrec; /* The actual mft record of the inode. */ + ntfs_volume *vol; /* Pointer to the ntfs volume of this inode. */ + unsigned long state; /* NTFS specific flags describing this inode. + See ntfs_inode_state_bits above. */ + FILE_ATTR_FLAGS flags; /* Flags describing the file. + (Copy from STANDARD_INFORMATION) */ + /* + * Attribute list support (for use by the attribute lookup functions). + * Setup during ntfs_open_inode() for all inodes with attribute lists. + * Only valid if NI_AttrList is set in state. + */ + u32 attr_list_size; /* Length of attribute list value in bytes. */ + u8 *attr_list; /* Attribute list value itself. */ + /* Below fields are always valid. */ + s32 nr_extents; /* For a base mft record, the number of + attached extent inodes (0 if none), for + extent records this is -1. */ + union { /* This union is only used if nr_extents != 0. */ + ntfs_inode **extent_nis;/* For nr_extents > 0, array of the + ntfs inodes of the extent mft + records belonging to this base + inode which have been loaded. */ + ntfs_inode *base_ni; /* For nr_extents == -1, the ntfs + inode of the base mft record. */ + }; + + /* Below fields are valid only for base inode. */ + + /* + * These two fields are used to sync filename index and guaranteed to be + * correct, however value in index itself maybe wrong (windows itself + * do not update them properly). + * For directories, they hold the index size, provided the + * flag KnownSize is set. + */ + s64 data_size; /* Data size of unnamed DATA attribute + (or INDEX_ROOT for directories) */ + s64 allocated_size; /* Allocated size stored in the filename + index. (NOTE: Equal to allocated size of + the unnamed data attribute for normal or + encrypted files and to compressed size + of the unnamed data attribute for sparse or + compressed files.) */ + + /* + * These four fields are copy of relevant fields from + * STANDARD_INFORMATION attribute and used to sync it and FILE_NAME + * attribute in the index. + */ + ntfs_time creation_time; + ntfs_time last_data_change_time; + ntfs_time last_mft_change_time; + ntfs_time last_access_time; + /* NTFS 3.x extensions added by JPA */ + /* only if NI_v3_Extensions is set in state */ + le32 owner_id; + le32 security_id; + le64 quota_charged; + le64 usn; +}; + +typedef enum { + NTFS_UPDATE_ATIME = 1 << 0, + NTFS_UPDATE_MTIME = 1 << 1, + NTFS_UPDATE_CTIME = 1 << 2, +} ntfs_time_update_flags; + +#define NTFS_UPDATE_MCTIME (NTFS_UPDATE_MTIME | NTFS_UPDATE_CTIME) +#define NTFS_UPDATE_AMCTIME (NTFS_UPDATE_ATIME | NTFS_UPDATE_MCTIME) + +extern ntfs_inode *ntfs_inode_base(ntfs_inode *ni); + +extern ntfs_inode *ntfs_inode_allocate(ntfs_volume *vol); + +extern ntfs_inode *ntfs_inode_open(ntfs_volume *vol, const MFT_REF mref); + +extern int ntfs_inode_close(ntfs_inode *ni); +extern int ntfs_inode_close_in_dir(ntfs_inode *ni, ntfs_inode *dir_ni); + +#if CACHE_NIDATA_SIZE + +struct CACHED_GENERIC; + +extern int ntfs_inode_real_close(ntfs_inode *ni); +extern void ntfs_inode_invalidate(ntfs_volume *vol, const MFT_REF mref); +extern void ntfs_inode_nidata_free(const struct CACHED_GENERIC *cached); +extern int ntfs_inode_nidata_hash(const struct CACHED_GENERIC *item); + +#endif + + +extern ntfs_inode *ntfs_extent_inode_open(ntfs_inode *base_ni, + const MFT_REF mref); + +extern int ntfs_inode_attach_all_extents(ntfs_inode *ni); + +extern void ntfs_inode_mark_dirty(ntfs_inode *ni); + +extern void ntfs_inode_update_times(ntfs_inode *ni, ntfs_time_update_flags mask); + +extern int ntfs_inode_sync(ntfs_inode *ni); + +extern int ntfs_inode_add_attrlist(ntfs_inode *ni); + +extern int ntfs_inode_free_space(ntfs_inode *ni, int size); + +extern int ntfs_inode_badclus_bad(u64 mft_no, ATTR_RECORD *a); + +extern int ntfs_inode_get_times(ntfs_inode *ni, char *value, size_t size); + +extern int ntfs_inode_set_times(ntfs_inode *ni, const char *value, + size_t size, int flags); + +/* debugging */ +#define debug_double_inode(num, type) +#define debug_cached_inode(ni) + +#endif /* defined _NTFS_INODE_H */ diff --git a/include/ntfs-3g/layout.h b/include/ntfs-3g/layout.h new file mode 100755 index 0000000..8670557 --- a/dev/null +++ b/include/ntfs-3g/layout.h @@ -0,0 +1,2661 @@ +/* + * layout.h - Ntfs on-disk layout structures. Originated from the Linux-NTFS project. + * + * Copyright (c) 2000-2005 Anton Altaparmakov + * Copyright (c) 2005 Yura Pakhuchiy + * Copyright (c) 2005-2006 Szabolcs Szakacsits + * + * This program/include file 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/include file 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 (in the main directory of the NTFS-3G + * distribution in the file COPYING); if not, write to the Free Software + * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _NTFS_LAYOUT_H +#define _NTFS_LAYOUT_H + +#include "types.h" +#include "endians.h" +#include "support.h" + +/* The NTFS oem_id */ +#define magicNTFS const_cpu_to_le64(0x202020205346544e) /* "NTFS " */ +#define NTFS_SB_MAGIC 0x5346544e /* 'NTFS' */ + +/* + * Location of bootsector on partition: + * The standard NTFS_BOOT_SECTOR is on sector 0 of the partition. + * On NT4 and above there is one backup copy of the boot sector to + * be found on the last sector of the partition (not normally accessible + * from within Windows as the bootsector contained number of sectors + * value is one less than the actual value!). + * On versions of NT 3.51 and earlier, the backup copy was located at + * number of sectors/2 (integer divide), i.e. in the middle of the volume. + */ + +/** + * struct BIOS_PARAMETER_BLOCK - BIOS parameter block (bpb) structure. + */ +typedef struct { + u16 bytes_per_sector; /* Size of a sector in bytes. */ + u8 sectors_per_cluster; /* Size of a cluster in sectors. */ + u16 reserved_sectors; /* zero */ + u8 fats; /* zero */ + u16 root_entries; /* zero */ + u16 sectors; /* zero */ + u8 media_type; /* 0xf8 = hard disk */ + u16 sectors_per_fat; /* zero */ +/*0x0d*/u16 sectors_per_track; /* Required to boot Windows. */ +/*0x0f*/u16 heads; /* Required to boot Windows. */ +/*0x11*/u32 hidden_sectors; /* Offset to the start of the partition + relative to the disk in sectors. + Required to boot Windows. */ +/*0x15*/u32 large_sectors; /* zero */ +/* sizeof() = 25 (0x19) bytes */ +} __attribute__((__packed__)) BIOS_PARAMETER_BLOCK; + +/** + * struct NTFS_BOOT_SECTOR - NTFS boot sector structure. + */ +typedef struct { + u8 jump[3]; /* Irrelevant (jump to boot up code).*/ + u64 oem_id; /* Magic "NTFS ". */ +/*0x0b*/BIOS_PARAMETER_BLOCK bpb; /* See BIOS_PARAMETER_BLOCK. */ + u8 physical_drive; /* 0x00 floppy, 0x80 hard disk */ + u8 current_head; /* zero */ + u8 extended_boot_signature; /* 0x80 */ + u8 reserved2; /* zero */ +/*0x28*/s64 number_of_sectors; /* Number of sectors in volume. Gives + maximum volume size of 2^63 sectors. + Assuming standard sector size of 512 + bytes, the maximum byte size is + approx. 4.7x10^21 bytes. (-; */ + s64 mft_lcn; /* Cluster location of mft data. */ + s64 mftmirr_lcn; /* Cluster location of copy of mft. */ + s8 clusters_per_mft_record; /* Mft record size in clusters. */ + u8 reserved0[3]; /* zero */ + s8 clusters_per_index_record; /* Index block size in clusters. */ + u8 reserved1[3]; /* zero */ + u64 volume_serial_number; /* Irrelevant (serial number). */ + u32 checksum; /* Boot sector checksum. */ +/*0x54*/u8 bootstrap[426]; /* Irrelevant (boot up code). */ + u16 end_of_sector_marker; /* End of bootsector magic. Always is + 0xaa55 in little endian. */ +/* sizeof() = 512 (0x200) bytes */ +} __attribute__((__packed__)) NTFS_BOOT_SECTOR; + +/** + * enum NTFS_RECORD_TYPES - + * + * Magic identifiers present at the beginning of all ntfs record containing + * records (like mft records for example). + */ +typedef enum { + /* Found in $MFT/$DATA. */ + magic_FILE = const_cpu_to_le32(0x454c4946), /* Mft entry. */ + magic_INDX = const_cpu_to_le32(0x58444e49), /* Index buffer. */ + magic_HOLE = const_cpu_to_le32(0x454c4f48), /* ? (NTFS 3.0+?) */ + + /* Found in $LogFile/$DATA. */ + magic_RSTR = const_cpu_to_le32(0x52545352), /* Restart page. */ + magic_RCRD = const_cpu_to_le32(0x44524352), /* Log record page. */ + + /* Found in $LogFile/$DATA. (May be found in $MFT/$DATA, also?) */ + magic_CHKD = const_cpu_to_le32(0x444b4843), /* Modified by chkdsk. */ + + /* Found in all ntfs record containing records. */ + magic_BAAD = const_cpu_to_le32(0x44414142), /* Failed multi sector + transfer was detected. */ + + /* + * Found in $LogFile/$DATA when a page is full or 0xff bytes and is + * thus not initialized. User has to initialize the page before using + * it. + */ + magic_empty = const_cpu_to_le32(0xffffffff),/* Record is empty and has + to be initialized before + it can be used. */ +} NTFS_RECORD_TYPES; + +/* + * Generic magic comparison macros. Finally found a use for the ## preprocessor + * operator! (-8 + */ +#define ntfs_is_magic(x, m) ( (u32)(x) == (u32)magic_##m ) +#define ntfs_is_magicp(p, m) ( *(u32*)(p) == (u32)magic_##m ) + +/* + * Specialised magic comparison macros for the NTFS_RECORD_TYPES defined above. + */ +#define ntfs_is_file_record(x) ( ntfs_is_magic (x, FILE) ) +#define ntfs_is_file_recordp(p) ( ntfs_is_magicp(p, FILE) ) +#define ntfs_is_mft_record(x) ( ntfs_is_file_record(x) ) +#define ntfs_is_mft_recordp(p) ( ntfs_is_file_recordp(p) ) +#define ntfs_is_indx_record(x) ( ntfs_is_magic (x, INDX) ) +#define ntfs_is_indx_recordp(p) ( ntfs_is_magicp(p, INDX) ) +#define ntfs_is_hole_record(x) ( ntfs_is_magic (x, HOLE) ) +#define ntfs_is_hole_recordp(p) ( ntfs_is_magicp(p, HOLE) ) + +#define ntfs_is_rstr_record(x) ( ntfs_is_magic (x, RSTR) ) +#define ntfs_is_rstr_recordp(p) ( ntfs_is_magicp(p, RSTR) ) +#define ntfs_is_rcrd_record(x) ( ntfs_is_magic (x, RCRD) ) +#define ntfs_is_rcrd_recordp(p) ( ntfs_is_magicp(p, RCRD) ) + +#define ntfs_is_chkd_record(x) ( ntfs_is_magic (x, CHKD) ) +#define ntfs_is_chkd_recordp(p) ( ntfs_is_magicp(p, CHKD) ) + +#define ntfs_is_baad_record(x) ( ntfs_is_magic (x, BAAD) ) +#define ntfs_is_baad_recordp(p) ( ntfs_is_magicp(p, BAAD) ) + +#define ntfs_is_empty_record(x) ( ntfs_is_magic (x, empty) ) +#define ntfs_is_empty_recordp(p) ( ntfs_is_magicp(p, empty) ) + + +#define NTFS_BLOCK_SIZE 512 +#define NTFS_BLOCK_SIZE_BITS 9 + +/** + * struct NTFS_RECORD - + * + * The Update Sequence Array (usa) is an array of the u16 values which belong + * to the end of each sector protected by the update sequence record in which + * this array is contained. Note that the first entry is the Update Sequence + * Number (usn), a cyclic counter of how many times the protected record has + * been written to disk. The values 0 and -1 (ie. 0xffff) are not used. All + * last u16's of each sector have to be equal to the usn (during reading) or + * are set to it (during writing). If they are not, an incomplete multi sector + * transfer has occurred when the data was written. + * The maximum size for the update sequence array is fixed to: + * maximum size = usa_ofs + (usa_count * 2) = 510 bytes + * The 510 bytes comes from the fact that the last u16 in the array has to + * (obviously) finish before the last u16 of the first 512-byte sector. + * This formula can be used as a consistency check in that usa_ofs + + * (usa_count * 2) has to be less than or equal to 510. + */ +typedef struct { + NTFS_RECORD_TYPES magic;/* A four-byte magic identifying the + record type and/or status. */ + u16 usa_ofs; /* Offset to the Update Sequence Array (usa) + from the start of the ntfs record. */ + u16 usa_count; /* Number of u16 sized entries in the usa + including the Update Sequence Number (usn), + thus the number of fixups is the usa_count + minus 1. */ +} __attribute__((__packed__)) NTFS_RECORD; + +/** + * enum NTFS_SYSTEM_FILES - System files mft record numbers. + * + * All these files are always marked as used in the bitmap attribute of the + * mft; presumably in order to avoid accidental allocation for random other + * mft records. Also, the sequence number for each of the system files is + * always equal to their mft record number and it is never modified. + */ +typedef enum { + FILE_MFT = 0, /* Master file table (mft). Data attribute + contains the entries and bitmap attribute + records which ones are in use (bit==1). */ + FILE_MFTMirr = 1, /* Mft mirror: copy of first four mft records + in data attribute. If cluster size > 4kiB, + copy of first N mft records, with + N = cluster_size / mft_record_size. */ + FILE_LogFile = 2, /* Journalling log in data attribute. */ + FILE_Volume = 3, /* Volume name attribute and volume information + attribute (flags and ntfs version). Windows + refers to this file as volume DASD (Direct + Access Storage Device). */ + FILE_AttrDef = 4, /* Array of attribute definitions in data + attribute. */ + FILE_root = 5, /* Root directory. */ + FILE_Bitmap = 6, /* Allocation bitmap of all clusters (lcns) in + data attribute. */ + FILE_Boot = 7, /* Boot sector (always at cluster 0) in data + attribute. */ + FILE_BadClus = 8, /* Contains all bad clusters in the non-resident + data attribute. */ + FILE_Secure = 9, /* Shared security descriptors in data attribute + and two indexes into the descriptors. + Appeared in Windows 2000. Before that, this + file was named $Quota but was unused. */ + FILE_UpCase = 10, /* Uppercase equivalents of all 65536 Unicode + characters in data attribute. */ + FILE_Extend = 11, /* Directory containing other system files (eg. + $ObjId, $Quota, $Reparse and $UsnJrnl). This + is new to NTFS3.0. */ + FILE_reserved12 = 12, /* Reserved for future use (records 12-15). */ + FILE_reserved13 = 13, + FILE_reserved14 = 14, + FILE_reserved15 = 15, + FILE_first_user = 16, /* First user file, used as test limit for + whether to allow opening a file or not. */ +} NTFS_SYSTEM_FILES; + +/** + * enum MFT_RECORD_FLAGS - + * + * These are the so far known MFT_RECORD_* flags (16-bit) which contain + * information about the mft record in which they are present. + * + * MFT_RECORD_IS_4 exists on all $Extend sub-files. + * It seems that it marks it is a metadata file with MFT record >24, however, + * it is unknown if it is limited to metadata files only. + * + * MFT_RECORD_IS_VIEW_INDEX exists on every metafile with a non directory + * index, that means an INDEX_ROOT and an INDEX_ALLOCATION with a name other + * than "$I30". It is unknown if it is limited to metadata files only. + */ +typedef enum { + MFT_RECORD_IN_USE = const_cpu_to_le16(0x0001), + MFT_RECORD_IS_DIRECTORY = const_cpu_to_le16(0x0002), + MFT_RECORD_IS_4 = const_cpu_to_le16(0x0004), + MFT_RECORD_IS_VIEW_INDEX = const_cpu_to_le16(0x0008), + MFT_REC_SPACE_FILLER = 0xffff, /* Just to make flags + 16-bit. */ +} __attribute__((__packed__)) MFT_RECORD_FLAGS; + +/* + * mft references (aka file references or file record segment references) are + * used whenever a structure needs to refer to a record in the mft. + * + * A reference consists of a 48-bit index into the mft and a 16-bit sequence + * number used to detect stale references. + * + * For error reporting purposes we treat the 48-bit index as a signed quantity. + * + * The sequence number is a circular counter (skipping 0) describing how many + * times the referenced mft record has been (re)used. This has to match the + * sequence number of the mft record being referenced, otherwise the reference + * is considered stale and removed (FIXME: only ntfsck or the driver itself?). + * + * If the sequence number is zero it is assumed that no sequence number + * consistency checking should be performed. + * + * FIXME: Since inodes are 32-bit as of now, the driver needs to always check + * for high_part being 0 and if not either BUG(), cause a panic() or handle + * the situation in some other way. This shouldn't be a problem as a volume has + * to become HUGE in order to need more than 32-bits worth of mft records. + * Assuming the standard mft record size of 1kb only the records (never mind + * the non-resident attributes, etc.) would require 4Tb of space on their own + * for the first 32 bits worth of records. This is only if some strange person + * doesn't decide to foul play and make the mft sparse which would be a really + * horrible thing to do as it would trash our current driver implementation. )-: + * Do I hear screams "we want 64-bit inodes!" ?!? (-; + * + * FIXME: The mft zone is defined as the first 12% of the volume. This space is + * reserved so that the mft can grow contiguously and hence doesn't become + * fragmented. Volume free space includes the empty part of the mft zone and + * when the volume's free 88% are used up, the mft zone is shrunk by a factor + * of 2, thus making more space available for more files/data. This process is + * repeated every time there is no more free space except for the mft zone until + * there really is no more free space. + */ + +/* + * Typedef the MFT_REF as a 64-bit value for easier handling. + * Also define two unpacking macros to get to the reference (MREF) and + * sequence number (MSEQNO) respectively. + * The _LE versions are to be applied on little endian MFT_REFs. + * Note: The _LE versions will return a CPU endian formatted value! + */ +#define MFT_REF_MASK_CPU 0x0000ffffffffffffULL +#define MFT_REF_MASK_LE const_cpu_to_le64(MFT_REF_MASK_CPU) + +typedef u64 MFT_REF; + +#define MK_MREF(m, s) ((MFT_REF)(((MFT_REF)(s) << 48) | \ + ((MFT_REF)(m) & MFT_REF_MASK_CPU))) +#define MK_LE_MREF(m, s) const_cpu_to_le64(((MFT_REF)(((MFT_REF)(s) << 48) | \ + ((MFT_REF)(m) & MFT_REF_MASK_CPU)))) + +#define MREF(x) ((u64)((x) & MFT_REF_MASK_CPU)) +#define MSEQNO(x) ((u16)(((x) >> 48) & 0xffff)) +#define MREF_LE(x) ((u64)(const_le64_to_cpu(x) & MFT_REF_MASK_CPU)) +#define MSEQNO_LE(x) ((u16)((const_le64_to_cpu(x) >> 48) & 0xffff)) + +#define IS_ERR_MREF(x) (((x) & 0x0000800000000000ULL) ? 1 : 0) +#define ERR_MREF(x) ((u64)((s64)(x))) +#define MREF_ERR(x) ((int)((s64)(x))) + +/** + * struct MFT_RECORD - An MFT record layout (NTFS 3.1+) + * + * The mft record header present at the beginning of every record in the mft. + * This is followed by a sequence of variable length attribute records which + * is terminated by an attribute of type AT_END which is a truncated attribute + * in that it only consists of the attribute type code AT_END and none of the + * other members of the attribute structure are present. + */ +typedef struct { +/*Ofs*/ +/* 0 NTFS_RECORD; -- Unfolded here as gcc doesn't like unnamed structs. */ + NTFS_RECORD_TYPES magic;/* Usually the magic is "FILE". */ + u16 usa_ofs; /* See NTFS_RECORD definition above. */ + u16 usa_count; /* See NTFS_RECORD definition above. */ + +/* 8*/ LSN lsn; /* $LogFile sequence number for this record. + Changed every time the record is modified. */ +/* 16*/ u16 sequence_number; /* Number of times this mft record has been + reused. (See description for MFT_REF + above.) NOTE: The increment (skipping zero) + is done when the file is deleted. NOTE: If + this is zero it is left zero. */ +/* 18*/ u16 link_count; /* Number of hard links, i.e. the number of + directory entries referencing this record. + NOTE: Only used in mft base records. + NOTE: When deleting a directory entry we + check the link_count and if it is 1 we + delete the file. Otherwise we delete the + FILE_NAME_ATTR being referenced by the + directory entry from the mft record and + decrement the link_count. + FIXME: Careful with Win32 + DOS names! */ +/* 20*/ u16 attrs_offset; /* Byte offset to the first attribute in this + mft record from the start of the mft record. + NOTE: Must be aligned to 8-byte boundary. */ +/* 22*/ MFT_RECORD_FLAGS flags; /* Bit array of MFT_RECORD_FLAGS. When a file + is deleted, the MFT_RECORD_IN_USE flag is + set to zero. */ +/* 24*/ u32 bytes_in_use; /* Number of bytes used in this mft record. + NOTE: Must be aligned to 8-byte boundary. */ +/* 28*/ u32 bytes_allocated; /* Number of bytes allocated for this mft + record. This should be equal to the mft + record size. */ +/* 32*/ MFT_REF base_mft_record; /* This is zero for base mft records. + When it is not zero it is a mft reference + pointing to the base mft record to which + this record belongs (this is then used to + locate the attribute list attribute present + in the base record which describes this + extension record and hence might need + modification when the extension record + itself is modified, also locating the + attribute list also means finding the other + potential extents, belonging to the non-base + mft record). */ +/* 40*/ u16 next_attr_instance; /* The instance number that will be + assigned to the next attribute added to this + mft record. NOTE: Incremented each time + after it is used. NOTE: Every time the mft + record is reused this number is set to zero. + NOTE: The first instance number is always 0. + */ +/* The below fields are specific to NTFS 3.1+ (Windows XP and above): */ +/* 42*/ u16 reserved; /* Reserved/alignment. */ +/* 44*/ u32 mft_record_number; /* Number of this mft record. */ +/* sizeof() = 48 bytes */ +/* + * When (re)using the mft record, we place the update sequence array at this + * offset, i.e. before we start with the attributes. This also makes sense, + * otherwise we could run into problems with the update sequence array + * containing in itself the last two bytes of a sector which would mean that + * multi sector transfer protection wouldn't work. As you can't protect data + * by overwriting it since you then can't get it back... + * When reading we obviously use the data from the ntfs record header. + */ +} __attribute__((__packed__)) MFT_RECORD; + +/** + * struct MFT_RECORD_OLD - An MFT record layout (NTFS <=3.0) + * + * This is the version without the NTFS 3.1+ specific fields. + */ +typedef struct { +/*Ofs*/ +/* 0 NTFS_RECORD; -- Unfolded here as gcc doesn't like unnamed structs. */ + NTFS_RECORD_TYPES magic;/* Usually the magic is "FILE". */ + u16 usa_ofs; /* See NTFS_RECORD definition above. */ + u16 usa_count; /* See NTFS_RECORD definition above. */ + +/* 8*/ LSN lsn; /* $LogFile sequence number for this record. + Changed every time the record is modified. */ +/* 16*/ u16 sequence_number; /* Number of times this mft record has been + reused. (See description for MFT_REF + above.) NOTE: The increment (skipping zero) + is done when the file is deleted. NOTE: If + this is zero it is left zero. */ +/* 18*/ u16 link_count; /* Number of hard links, i.e. the number of + directory entries referencing this record. + NOTE: Only used in mft base records. + NOTE: When deleting a directory entry we + check the link_count and if it is 1 we + delete the file. Otherwise we delete the + FILE_NAME_ATTR being referenced by the + directory entry from the mft record and + decrement the link_count. + FIXME: Careful with Win32 + DOS names! */ +/* 20*/ u16 attrs_offset; /* Byte offset to the first attribute in this + mft record from the start of the mft record. + NOTE: Must be aligned to 8-byte boundary. */ +/* 22*/ MFT_RECORD_FLAGS flags; /* Bit array of MFT_RECORD_FLAGS. When a file + is deleted, the MFT_RECORD_IN_USE flag is + set to zero. */ +/* 24*/ u32 bytes_in_use; /* Number of bytes used in this mft record. + NOTE: Must be aligned to 8-byte boundary. */ +/* 28*/ u32 bytes_allocated; /* Number of bytes allocated for this mft + record. This should be equal to the mft + record size. */ +/* 32*/ MFT_REF base_mft_record; /* This is zero for base mft records. + When it is not zero it is a mft reference + pointing to the base mft record to which + this record belongs (this is then used to + locate the attribute list attribute present + in the base record which describes this + extension record and hence might need + modification when the extension record + itself is modified, also locating the + attribute list also means finding the other + potential extents, belonging to the non-base + mft record). */ +/* 40*/ u16 next_attr_instance; /* The instance number that will be + assigned to the next attribute added to this + mft record. NOTE: Incremented each time + after it is used. NOTE: Every time the mft + record is reused this number is set to zero. + NOTE: The first instance number is always 0. + */ +/* sizeof() = 42 bytes */ +/* + * When (re)using the mft record, we place the update sequence array at this + * offset, i.e. before we start with the attributes. This also makes sense, + * otherwise we could run into problems with the update sequence array + * containing in itself the last two bytes of a sector which would mean that + * multi sector transfer protection wouldn't work. As you can't protect data + * by overwriting it since you then can't get it back... + * When reading we obviously use the data from the ntfs record header. + */ +} __attribute__((__packed__)) MFT_RECORD_OLD; + +/** + * enum ATTR_TYPES - System defined attributes (32-bit). + * + * Each attribute type has a corresponding attribute name (Unicode string of + * maximum 64 character length) as described by the attribute definitions + * present in the data attribute of the $AttrDef system file. + * + * On NTFS 3.0 volumes the names are just as the types are named in the below + * enum exchanging AT_ for the dollar sign ($). If that isn't a revealing + * choice of symbol... (-; + */ +typedef enum { + AT_UNUSED = const_cpu_to_le32( 0), + AT_STANDARD_INFORMATION = const_cpu_to_le32( 0x10), + AT_ATTRIBUTE_LIST = const_cpu_to_le32( 0x20), + AT_FILE_NAME = const_cpu_to_le32( 0x30), + AT_OBJECT_ID = const_cpu_to_le32( 0x40), + AT_SECURITY_DESCRIPTOR = const_cpu_to_le32( 0x50), + AT_VOLUME_NAME = const_cpu_to_le32( 0x60), + AT_VOLUME_INFORMATION = const_cpu_to_le32( 0x70), + AT_DATA = const_cpu_to_le32( 0x80), + AT_INDEX_ROOT = const_cpu_to_le32( 0x90), + AT_INDEX_ALLOCATION = const_cpu_to_le32( 0xa0), + AT_BITMAP = const_cpu_to_le32( 0xb0), + AT_REPARSE_POINT = const_cpu_to_le32( 0xc0), + AT_EA_INFORMATION = const_cpu_to_le32( 0xd0), + AT_EA = const_cpu_to_le32( 0xe0), + AT_PROPERTY_SET = const_cpu_to_le32( 0xf0), + AT_LOGGED_UTILITY_STREAM = const_cpu_to_le32( 0x100), + AT_FIRST_USER_DEFINED_ATTRIBUTE = const_cpu_to_le32( 0x1000), + AT_END = const_cpu_to_le32(0xffffffff), +} ATTR_TYPES; + +/** + * enum COLLATION_RULES - The collation rules for sorting views/indexes/etc + * (32-bit). + * + * COLLATION_UNICODE_STRING - Collate Unicode strings by comparing their binary + * Unicode values, except that when a character can be uppercased, the + * upper case value collates before the lower case one. + * COLLATION_FILE_NAME - Collate file names as Unicode strings. The collation + * is done very much like COLLATION_UNICODE_STRING. In fact I have no idea + * what the difference is. Perhaps the difference is that file names + * would treat some special characters in an odd way (see + * unistr.c::ntfs_collate_names() and unistr.c::legal_ansi_char_array[] + * for what I mean but COLLATION_UNICODE_STRING would not give any special + * treatment to any characters at all, but this is speculation. + * COLLATION_NTOFS_ULONG - Sorting is done according to ascending u32 key + * values. E.g. used for $SII index in FILE_Secure, which sorts by + * security_id (u32). + * COLLATION_NTOFS_SID - Sorting is done according to ascending SID values. + * E.g. used for $O index in FILE_Extend/$Quota. + * COLLATION_NTOFS_SECURITY_HASH - Sorting is done first by ascending hash + * values and second by ascending security_id values. E.g. used for $SDH + * index in FILE_Secure. + * COLLATION_NTOFS_ULONGS - Sorting is done according to a sequence of ascending + * u32 key values. E.g. used for $O index in FILE_Extend/$ObjId, which + * sorts by object_id (16-byte), by splitting up the object_id in four + * u32 values and using them as individual keys. E.g. take the following + * two security_ids, stored as follows on disk: + * 1st: a1 61 65 b7 65 7b d4 11 9e 3d 00 e0 81 10 42 59 + * 2nd: 38 14 37 d2 d2 f3 d4 11 a5 21 c8 6b 79 b1 97 45 + * To compare them, they are split into four u32 values each, like so: + * 1st: 0xb76561a1 0x11d47b65 0xe0003d9e 0x59421081 + * 2nd: 0xd2371438 0x11d4f3d2 0x6bc821a5 0x4597b179 + * Now, it is apparent why the 2nd object_id collates after the 1st: the + * first u32 value of the 1st object_id is less than the first u32 of + * the 2nd object_id. If the first u32 values of both object_ids were + * equal then the second u32 values would be compared, etc. + */ +typedef enum { + COLLATION_BINARY = const_cpu_to_le32(0), /* Collate by binary + compare where the first byte is most + significant. */ + COLLATION_FILE_NAME = const_cpu_to_le32(1), /* Collate file names + as Unicode strings. */ + COLLATION_UNICODE_STRING = const_cpu_to_le32(2), /* Collate Unicode + strings by comparing their binary + Unicode values, except that when a + character can be uppercased, the upper + case value collates before the lower + case one. */ + COLLATION_NTOFS_ULONG = const_cpu_to_le32(16), + COLLATION_NTOFS_SID = const_cpu_to_le32(17), + COLLATION_NTOFS_SECURITY_HASH = const_cpu_to_le32(18), + COLLATION_NTOFS_ULONGS = const_cpu_to_le32(19), +} COLLATION_RULES; + +/** + * enum ATTR_DEF_FLAGS - + * + * The flags (32-bit) describing attribute properties in the attribute + * definition structure. FIXME: This information is based on Regis's + * information and, according to him, it is not certain and probably + * incomplete. The INDEXABLE flag is fairly certainly correct as only the file + * name attribute has this flag set and this is the only attribute indexed in + * NT4. + */ +typedef enum { + ATTR_DEF_INDEXABLE = const_cpu_to_le32(0x02), /* Attribute can be + indexed. */ + ATTR_DEF_MULTIPLE = const_cpu_to_le32(0x04), /* Attribute type + can be present multiple times in the + mft records of an inode. */ + ATTR_DEF_NOT_ZERO = const_cpu_to_le32(0x08), /* Attribute value + must contain at least one non-zero + byte. */ + ATTR_DEF_INDEXED_UNIQUE = const_cpu_to_le32(0x10), /* Attribute must be + indexed and the attribute value must be + unique for the attribute type in all of + the mft records of an inode. */ + ATTR_DEF_NAMED_UNIQUE = const_cpu_to_le32(0x20), /* Attribute must be + named and the name must be unique for + the attribute type in all of the mft + records of an inode. */ + ATTR_DEF_RESIDENT = const_cpu_to_le32(0x40), /* Attribute must be + resident. */ + ATTR_DEF_ALWAYS_LOG = const_cpu_to_le32(0x80), /* Always log + modifications to this attribute, + regardless of whether it is resident or + non-resident. Without this, only log + modifications if the attribute is + resident. */ +} ATTR_DEF_FLAGS; + +/** + * struct ATTR_DEF - + * + * The data attribute of FILE_AttrDef contains a sequence of attribute + * definitions for the NTFS volume. With this, it is supposed to be safe for an + * older NTFS driver to mount a volume containing a newer NTFS version without + * damaging it (that's the theory. In practice it's: not damaging it too much). + * Entries are sorted by attribute type. The flags describe whether the + * attribute can be resident/non-resident and possibly other things, but the + * actual bits are unknown. + */ +typedef struct { +/*hex ofs*/ +/* 0*/ ntfschar name[0x40]; /* Unicode name of the attribute. Zero + terminated. */ +/* 80*/ ATTR_TYPES type; /* Type of the attribute. */ +/* 84*/ u32 display_rule; /* Default display rule. + FIXME: What does it mean? (AIA) */ +/* 88*/ COLLATION_RULES collation_rule; /* Default collation rule. */ +/* 8c*/ ATTR_DEF_FLAGS flags; /* Flags describing the attribute. */ +/* 90*/ s64 min_size; /* Optional minimum attribute size. */ +/* 98*/ s64 max_size; /* Maximum size of attribute. */ +/* sizeof() = 0xa0 or 160 bytes */ +} __attribute__((__packed__)) ATTR_DEF; + +/** + * enum ATTR_FLAGS - Attribute flags (16-bit). + */ +typedef enum { + ATTR_IS_COMPRESSED = const_cpu_to_le16(0x0001), + ATTR_COMPRESSION_MASK = const_cpu_to_le16(0x00ff), /* Compression + method mask. Also, first + illegal value. */ + ATTR_IS_ENCRYPTED = const_cpu_to_le16(0x4000), + ATTR_IS_SPARSE = const_cpu_to_le16(0x8000), +} __attribute__((__packed__)) ATTR_FLAGS; + +/* + * Attribute compression. + * + * Only the data attribute is ever compressed in the current ntfs driver in + * Windows. Further, compression is only applied when the data attribute is + * non-resident. Finally, to use compression, the maximum allowed cluster size + * on a volume is 4kib. + * + * The compression method is based on independently compressing blocks of X + * clusters, where X is determined from the compression_unit value found in the + * non-resident attribute record header (more precisely: X = 2^compression_unit + * clusters). On Windows NT/2k, X always is 16 clusters (compression_unit = 4). + * + * There are three different cases of how a compression block of X clusters + * can be stored: + * + * 1) The data in the block is all zero (a sparse block): + * This is stored as a sparse block in the runlist, i.e. the runlist + * entry has length = X and lcn = -1. The mapping pairs array actually + * uses a delta_lcn value length of 0, i.e. delta_lcn is not present at + * all, which is then interpreted by the driver as lcn = -1. + * NOTE: Even uncompressed files can be sparse on NTFS 3.0 volumes, then + * the same principles apply as above, except that the length is not + * restricted to being any particular value. + * + * 2) The data in the block is not compressed: + * This happens when compression doesn't reduce the size of the block + * in clusters. I.e. if compression has a small effect so that the + * compressed data still occupies X clusters, then the uncompressed data + * is stored in the block. + * This case is recognised by the fact that the runlist entry has + * length = X and lcn >= 0. The mapping pairs array stores this as + * normal with a run length of X and some specific delta_lcn, i.e. + * delta_lcn has to be present. + * + * 3) The data in the block is compressed: + * The common case. This case is recognised by the fact that the run + * list entry has length L < X and lcn >= 0. The mapping pairs array + * stores this as normal with a run length of X and some specific + * delta_lcn, i.e. delta_lcn has to be present. This runlist entry is + * immediately followed by a sparse entry with length = X - L and + * lcn = -1. The latter entry is to make up the vcn counting to the + * full compression block size X. + * + * In fact, life is more complicated because adjacent entries of the same type + * can be coalesced. This means that one has to keep track of the number of + * clusters handled and work on a basis of X clusters at a time being one + * block. An example: if length L > X this means that this particular runlist + * entry contains a block of length X and part of one or more blocks of length + * L - X. Another example: if length L < X, this does not necessarily mean that + * the block is compressed as it might be that the lcn changes inside the block + * and hence the following runlist entry describes the continuation of the + * potentially compressed block. The block would be compressed if the + * following runlist entry describes at least X - L sparse clusters, thus + * making up the compression block length as described in point 3 above. (Of + * course, there can be several runlist entries with small lengths so that the + * sparse entry does not follow the first data containing entry with + * length < X.) + * + * NOTE: At the end of the compressed attribute value, there most likely is not + * just the right amount of data to make up a compression block, thus this data + * is not even attempted to be compressed. It is just stored as is, unless + * the number of clusters it occupies is reduced when compressed in which case + * it is stored as a compressed compression block, complete with sparse + * clusters at the end. + */ + +/** + * enum RESIDENT_ATTR_FLAGS - Flags of resident attributes (8-bit). + */ +typedef enum { + RESIDENT_ATTR_IS_INDEXED = 0x01, /* Attribute is referenced in an index + (has implications for deleting and + modifying the attribute). */ +} __attribute__((__packed__)) RESIDENT_ATTR_FLAGS; + +/** + * struct ATTR_RECORD - Attribute record header. + * + * Always aligned to 8-byte boundary. + */ +typedef struct { +/*Ofs*/ +/* 0*/ ATTR_TYPES type; /* The (32-bit) type of the attribute. */ +/* 4*/ u32 length; /* Byte size of the resident part of the + attribute (aligned to 8-byte boundary). + Used to get to the next attribute. */ +/* 8*/ u8 non_resident; /* If 0, attribute is resident. + If 1, attribute is non-resident. */ +/* 9*/ u8 name_length; /* Unicode character size of name of attribute. + 0 if unnamed. */ +/* 10*/ u16 name_offset; /* If name_length != 0, the byte offset to the + beginning of the name from the attribute + record. Note that the name is stored as a + Unicode string. When creating, place offset + just at the end of the record header. Then, + follow with attribute value or mapping pairs + array, resident and non-resident attributes + respectively, aligning to an 8-byte + boundary. */ +/* 12*/ ATTR_FLAGS flags; /* Flags describing the attribute. */ +/* 14*/ u16 instance; /* The instance of this attribute record. This + number is unique within this mft record (see + MFT_RECORD/next_attribute_instance notes + above for more details). */ +/* 16*/ union { + /* Resident attributes. */ + struct { +/* 16 */ u32 value_length; /* Byte size of attribute value. */ +/* 20 */ u16 value_offset; /* Byte offset of the attribute + value from the start of the + attribute record. When creating, + align to 8-byte boundary if we + have a name present as this might + not have a length of a multiple + of 8-bytes. */ +/* 22 */ RESIDENT_ATTR_FLAGS resident_flags; /* See above. */ +/* 23 */ s8 reservedR; /* Reserved/alignment to 8-byte + boundary. */ +/* 24 */ void *resident_end[0]; /* Use offsetof(ATTR_RECORD, + resident_end) to get size of + a resident attribute. */ + } __attribute__((__packed__)); + /* Non-resident attributes. */ + struct { +/* 16*/ VCN lowest_vcn; /* Lowest valid virtual cluster number + for this portion of the attribute value or + 0 if this is the only extent (usually the + case). - Only when an attribute list is used + does lowest_vcn != 0 ever occur. */ +/* 24*/ VCN highest_vcn; /* Highest valid vcn of this extent of + the attribute value. - Usually there is only one + portion, so this usually equals the attribute + value size in clusters minus 1. Can be -1 for + zero length files. Can be 0 for "single extent" + attributes. */ +/* 32*/ u16 mapping_pairs_offset; /* Byte offset from the + beginning of the structure to the mapping pairs + array which contains the mappings between the + vcns and the logical cluster numbers (lcns). + When creating, place this at the end of this + record header aligned to 8-byte boundary. */ +/* 34*/ u8 compression_unit; /* The compression unit expressed + as the log to the base 2 of the number of + clusters in a compression unit. 0 means not + compressed. (This effectively limits the + compression unit size to be a power of two + clusters.) WinNT4 only uses a value of 4. */ +/* 35*/ u8 reserved1[5]; /* Align to 8-byte boundary. */ +/* The sizes below are only used when lowest_vcn is zero, as otherwise it would + be difficult to keep them up-to-date.*/ +/* 40*/ s64 allocated_size; /* Byte size of disk space + allocated to hold the attribute value. Always + is a multiple of the cluster size. When a file + is compressed, this field is a multiple of the + compression block size (2^compression_unit) and + it represents the logically allocated space + rather than the actual on disk usage. For this + use the compressed_size (see below). */ +/* 48*/ s64 data_size; /* Byte size of the attribute + value. Can be larger than allocated_size if + attribute value is compressed or sparse. */ +/* 56*/ s64 initialized_size; /* Byte size of initialized + portion of the attribute value. Usually equals + data_size. */ +/* 64 */ void *non_resident_end[0]; /* Use offsetof(ATTR_RECORD, + non_resident_end) to get + size of a non resident + attribute. */ +/* sizeof(uncompressed attr) = 64*/ +/* 64*/ s64 compressed_size; /* Byte size of the attribute + value after compression. Only present when + compressed. Always is a multiple of the + cluster size. Represents the actual amount of + disk space being used on the disk. */ +/* 72 */ void *compressed_end[0]; + /* Use offsetof(ATTR_RECORD, compressed_end) to + get size of a compressed attribute. */ +/* sizeof(compressed attr) = 72*/ + } __attribute__((__packed__)); + } __attribute__((__packed__)); +} __attribute__((__packed__)) ATTR_RECORD; + +typedef ATTR_RECORD ATTR_REC; + +/** + * enum FILE_ATTR_FLAGS - File attribute flags (32-bit). + */ +typedef enum { + /* + * These flags are only present in the STANDARD_INFORMATION attribute + * (in the field file_attributes). + */ + FILE_ATTR_READONLY = const_cpu_to_le32(0x00000001), + FILE_ATTR_HIDDEN = const_cpu_to_le32(0x00000002), + FILE_ATTR_SYSTEM = const_cpu_to_le32(0x00000004), + /* Old DOS volid. Unused in NT. = cpu_to_le32(0x00000008), */ + + FILE_ATTR_DIRECTORY = const_cpu_to_le32(0x00000010), + /* FILE_ATTR_DIRECTORY is not considered valid in NT. It is reserved + for the DOS SUBDIRECTORY flag. */ + FILE_ATTR_ARCHIVE = const_cpu_to_le32(0x00000020), + FILE_ATTR_DEVICE = const_cpu_to_le32(0x00000040), + FILE_ATTR_NORMAL = const_cpu_to_le32(0x00000080), + + FILE_ATTR_TEMPORARY = const_cpu_to_le32(0x00000100), + FILE_ATTR_SPARSE_FILE = const_cpu_to_le32(0x00000200), + FILE_ATTR_REPARSE_POINT = const_cpu_to_le32(0x00000400), + FILE_ATTR_COMPRESSED = const_cpu_to_le32(0x00000800), + + FILE_ATTR_OFFLINE = const_cpu_to_le32(0x00001000), + FILE_ATTR_NOT_CONTENT_INDEXED = const_cpu_to_le32(0x00002000), + FILE_ATTR_ENCRYPTED = const_cpu_to_le32(0x00004000), + + FILE_ATTR_VALID_FLAGS = const_cpu_to_le32(0x00007fb7), + /* FILE_ATTR_VALID_FLAGS masks out the old DOS VolId and the + FILE_ATTR_DEVICE and preserves everything else. This mask + is used to obtain all flags that are valid for reading. */ + FILE_ATTR_VALID_SET_FLAGS = const_cpu_to_le32(0x000031a7), + /* FILE_ATTR_VALID_SET_FLAGS masks out the old DOS VolId, the + FILE_ATTR_DEVICE, FILE_ATTR_DIRECTORY, FILE_ATTR_SPARSE_FILE, + FILE_ATTR_REPARSE_POINT, FILE_ATRE_COMPRESSED and FILE_ATTR_ENCRYPTED + and preserves the rest. This mask is used to to obtain all flags that + are valid for setting. */ + + /** + * FILE_ATTR_I30_INDEX_PRESENT - Is it a directory? + * + * This is a copy of the MFT_RECORD_IS_DIRECTORY bit from the mft + * record, telling us whether this is a directory or not, i.e. whether + * it has an index root attribute named "$I30" or not. + * + * This flag is only present in the FILE_NAME attribute (in the + * file_attributes field). + */ + FILE_ATTR_I30_INDEX_PRESENT = const_cpu_to_le32(0x10000000), + + /** + * FILE_ATTR_VIEW_INDEX_PRESENT - Does have a non-directory index? + * + * This is a copy of the MFT_RECORD_IS_VIEW_INDEX bit from the mft + * record, telling us whether this file has a view index present (eg. + * object id index, quota index, one of the security indexes and the + * reparse points index). + * + * This flag is only present in the $STANDARD_INFORMATION and + * $FILE_NAME attributes. + */ + FILE_ATTR_VIEW_INDEX_PRESENT = const_cpu_to_le32(0x20000000), +} __attribute__((__packed__)) FILE_ATTR_FLAGS; + +/* + * NOTE on times in NTFS: All times are in MS standard time format, i.e. they + * are the number of 100-nanosecond intervals since 1st January 1601, 00:00:00 + * universal coordinated time (UTC). (In Linux time starts 1st January 1970, + * 00:00:00 UTC and is stored as the number of 1-second intervals since then.) + */ + +/** + * struct STANDARD_INFORMATION - Attribute: Standard information (0x10). + * + * NOTE: Always resident. + * NOTE: Present in all base file records on a volume. + * NOTE: There is conflicting information about the meaning of each of the time + * fields but the meaning as defined below has been verified to be + * correct by practical experimentation on Windows NT4 SP6a and is hence + * assumed to be the one and only correct interpretation. + */ +typedef struct { +/*Ofs*/ +/* 0*/ s64 creation_time; /* Time file was created. Updated when + a filename is changed(?). */ +/* 8*/ s64 last_data_change_time; /* Time the data attribute was last + modified. */ +/* 16*/ s64 last_mft_change_time; /* Time this mft record was last + modified. */ +/* 24*/ s64 last_access_time; /* Approximate time when the file was + last accessed (obviously this is not + updated on read-only volumes). In + Windows this is only updated when + accessed if some time delta has + passed since the last update. Also, + last access times updates can be + disabled altogether for speed. */ +/* 32*/ FILE_ATTR_FLAGS file_attributes; /* Flags describing the file. */ +/* 36*/ union { + /* NTFS 1.2 (and previous, presumably) */ + struct { + /* 36 */ u8 reserved12[12]; /* Reserved/alignment to 8-byte + boundary. */ + /* 48 */ void *v1_end[0]; /* Marker for offsetof(). */ + } __attribute__((__packed__)); +/* sizeof() = 48 bytes */ + /* NTFS 3.0 */ + struct { +/* + * If a volume has been upgraded from a previous NTFS version, then these + * fields are present only if the file has been accessed since the upgrade. + * Recognize the difference by comparing the length of the resident attribute + * value. If it is 48, then the following fields are missing. If it is 72 then + * the fields are present. Maybe just check like this: + * if (resident.ValueLength < sizeof(STANDARD_INFORMATION)) { + * Assume NTFS 1.2- format. + * If (volume version is 3.0+) + * Upgrade attribute to NTFS 3.0 format. + * else + * Use NTFS 1.2- format for access. + * } else + * Use NTFS 3.0 format for access. + * Only problem is that it might be legal to set the length of the value to + * arbitrarily large values thus spoiling this check. - But chkdsk probably + * views that as a corruption, assuming that it behaves like this for all + * attributes. + */ + /* 36*/ u32 maximum_versions; /* Maximum allowed versions for + file. Zero if version numbering is disabled. */ + /* 40*/ u32 version_number; /* This file's version (if any). + Set to zero if maximum_versions is zero. */ + /* 44*/ u32 class_id; /* Class id from bidirectional + class id index (?). */ + /* 48*/ u32 owner_id; /* Owner_id of the user owning + the file. Translate via $Q index in FILE_Extend + /$Quota to the quota control entry for the user + owning the file. Zero if quotas are disabled. */ + /* 52*/ u32 security_id; /* Security_id for the file. + Translate via $SII index and $SDS data stream + in FILE_Secure to the security descriptor. */ + /* 56*/ u64 quota_charged; /* Byte size of the charge to + the quota for all streams of the file. Note: Is + zero if quotas are disabled. */ + /* 64*/ u64 usn; /* Last update sequence number + of the file. This is a direct index into the + change (aka usn) journal file. It is zero if + the usn journal is disabled. + NOTE: To disable the journal need to delete + the journal file itself and to then walk the + whole mft and set all Usn entries in all mft + records to zero! (This can take a while!) + The journal is FILE_Extend/$UsnJrnl. Win2k + will recreate the journal and initiate + logging if necessary when mounting the + partition. This, in contrast to disabling the + journal is a very fast process, so the user + won't even notice it. */ + /* 72*/ void *v3_end[0]; /* Marker for offsetof(). */ + } __attribute__((__packed__)); + } __attribute__((__packed__)); +/* sizeof() = 72 bytes (NTFS 3.0) */ +} __attribute__((__packed__)) STANDARD_INFORMATION; + +/** + * struct ATTR_LIST_ENTRY - Attribute: Attribute list (0x20). + * + * - Can be either resident or non-resident. + * - Value consists of a sequence of variable length, 8-byte aligned, + * ATTR_LIST_ENTRY records. + * - The attribute list attribute contains one entry for each attribute of + * the file in which the list is located, except for the list attribute + * itself. The list is sorted: first by attribute type, second by attribute + * name (if present), third by instance number. The extents of one + * non-resident attribute (if present) immediately follow after the initial + * extent. They are ordered by lowest_vcn and have their instance set to zero. + * It is not allowed to have two attributes with all sorting keys equal. + * - Further restrictions: + * - If not resident, the vcn to lcn mapping array has to fit inside the + * base mft record. + * - The attribute list attribute value has a maximum size of 256kb. This + * is imposed by the Windows cache manager. + * - Attribute lists are only used when the attributes of mft record do not + * fit inside the mft record despite all attributes (that can be made + * non-resident) having been made non-resident. This can happen e.g. when: + * - File has a large number of hard links (lots of file name + * attributes present). + * - The mapping pairs array of some non-resident attribute becomes so + * large due to fragmentation that it overflows the mft record. + * - The security descriptor is very complex (not applicable to + * NTFS 3.0 volumes). + * - There are many named streams. + */ +typedef struct { +/*Ofs*/ +/* 0*/ ATTR_TYPES type; /* Type of referenced attribute. */ +/* 4*/ u16 length; /* Byte size of this entry. */ +/* 6*/ u8 name_length; /* Size in Unicode chars of the name of the + attribute or 0 if unnamed. */ +/* 7*/ u8 name_offset; /* Byte offset to beginning of attribute name + (always set this to where the name would + start even if unnamed). */ +/* 8*/ VCN lowest_vcn; /* Lowest virtual cluster number of this portion + of the attribute value. This is usually 0. It + is non-zero for the case where one attribute + does not fit into one mft record and thus + several mft records are allocated to hold + this attribute. In the latter case, each mft + record holds one extent of the attribute and + there is one attribute list entry for each + extent. NOTE: This is DEFINITELY a signed + value! The windows driver uses cmp, followed + by jg when comparing this, thus it treats it + as signed. */ +/* 16*/ MFT_REF mft_reference; /* The reference of the mft record holding + the ATTR_RECORD for this portion of the + attribute value. */ +/* 24*/ u16 instance; /* If lowest_vcn = 0, the instance of the + attribute being referenced; otherwise 0. */ +/* 26*/ ntfschar name[0]; /* Use when creating only. When reading use + name_offset to determine the location of the + name. */ +/* sizeof() = 26 + (attribute_name_length * 2) bytes */ +} __attribute__((__packed__)) ATTR_LIST_ENTRY; + +/* + * The maximum allowed length for a file name. + */ +#define NTFS_MAX_NAME_LEN 255 + +/** + * enum FILE_NAME_TYPE_FLAGS - Possible namespaces for filenames in ntfs. + * (8-bit). + */ +typedef enum { + FILE_NAME_POSIX = 0x00, + /* This is the largest namespace. It is case sensitive and + allows all Unicode characters except for: '\0' and '/'. + Beware that in WinNT/2k files which eg have the same name + except for their case will not be distinguished by the + standard utilities and thus a "del filename" will delete + both "filename" and "fileName" without warning. */ + FILE_NAME_WIN32 = 0x01, + /* The standard WinNT/2k NTFS long filenames. Case insensitive. + All Unicode chars except: '\0', '"', '*', '/', ':', '<', + '>', '?', '\' and '|'. Further, names cannot end with a '.' + or a space. */ + FILE_NAME_DOS = 0x02, + /* The standard DOS filenames (8.3 format). Uppercase only. + All 8-bit characters greater space, except: '"', '*', '+', + ',', '/', ':', ';', '<', '=', '>', '?' and '\'. */ + FILE_NAME_WIN32_AND_DOS = 0x03, + /* 3 means that both the Win32 and the DOS filenames are + identical and hence have been saved in this single filename + record. */ +} __attribute__((__packed__)) FILE_NAME_TYPE_FLAGS; + +/** + * struct FILE_NAME_ATTR - Attribute: Filename (0x30). + * + * NOTE: Always resident. + * NOTE: All fields, except the parent_directory, are only updated when the + * filename is changed. Until then, they just become out of sync with + * reality and the more up to date values are present in the standard + * information attribute. + * NOTE: There is conflicting information about the meaning of each of the time + * fields but the meaning as defined below has been verified to be + * correct by practical experimentation on Windows NT4 SP6a and is hence + * assumed to be the one and only correct interpretation. + */ +typedef struct { +/*hex ofs*/ +/* 0*/ MFT_REF parent_directory; /* Directory this filename is + referenced from. */ +/* 8*/ s64 creation_time; /* Time file was created. */ +/* 10*/ s64 last_data_change_time; /* Time the data attribute was last + modified. */ +/* 18*/ s64 last_mft_change_time; /* Time this mft record was last + modified. */ +/* 20*/ s64 last_access_time; /* Last time this mft record was + accessed. */ +/* 28*/ s64 allocated_size; /* Byte size of on-disk allocated space + for the data attribute. So for + normal $DATA, this is the + allocated_size from the unnamed + $DATA attribute and for compressed + and/or sparse $DATA, this is the + compressed_size from the unnamed + $DATA attribute. NOTE: This is a + multiple of the cluster size. */ +/* 30*/ s64 data_size; /* Byte size of actual data in data + attribute. */ +/* 38*/ FILE_ATTR_FLAGS file_attributes; /* Flags describing the file. */ +/* 3c*/ union { + /* 3c*/ struct { + /* 3c*/ u16 packed_ea_size; /* Size of the buffer needed to + pack the extended attributes + (EAs), if such are present.*/ + /* 3e*/ u16 reserved; /* Reserved for alignment. */ + } __attribute__((__packed__)); + /* 3c*/ u32 reparse_point_tag; /* Type of reparse point, + present only in reparse + points and only if there are + no EAs. */ + } __attribute__((__packed__)); +/* 40*/ u8 file_name_length; /* Length of file name in + (Unicode) characters. */ +/* 41*/ FILE_NAME_TYPE_FLAGS file_name_type; /* Namespace of the file name.*/ +/* 42*/ ntfschar file_name[0]; /* File name in Unicode. */ +} __attribute__((__packed__)) FILE_NAME_ATTR; + +/** + * struct GUID - GUID structures store globally unique identifiers (GUID). + * + * A GUID is a 128-bit value consisting of one group of eight hexadecimal + * digits, followed by three groups of four hexadecimal digits each, followed + * by one group of twelve hexadecimal digits. GUIDs are Microsoft's + * implementation of the distributed computing environment (DCE) universally + * unique identifier (UUID). + * + * Example of a GUID: + * 1F010768-5A73-BC91-0010-A52216A7227B + */ +typedef struct { + u32 data1; /* The first eight hexadecimal digits of the GUID. */ + u16 data2; /* The first group of four hexadecimal digits. */ + u16 data3; /* The second group of four hexadecimal digits. */ + u8 data4[8]; /* The first two bytes are the third group of four + hexadecimal digits. The remaining six bytes are the + final 12 hexadecimal digits. */ +} __attribute__((__packed__)) GUID; + +/** + * struct OBJ_ID_INDEX_DATA - FILE_Extend/$ObjId contains an index named $O. + * + * This index contains all object_ids present on the volume as the index keys + * and the corresponding mft_record numbers as the index entry data parts. + * + * The data part (defined below) also contains three other object_ids: + * birth_volume_id - object_id of FILE_Volume on which the file was first + * created. Optional (i.e. can be zero). + * birth_object_id - object_id of file when it was first created. Usually + * equals the object_id. Optional (i.e. can be zero). + * domain_id - Reserved (always zero). + */ +typedef struct { + MFT_REF mft_reference; /* Mft record containing the object_id in + the index entry key. */ + union { + struct { + GUID birth_volume_id; + GUID birth_object_id; + GUID domain_id; + } __attribute__((__packed__)); + u8 extended_info[48]; + } __attribute__((__packed__)); +} __attribute__((__packed__)) OBJ_ID_INDEX_DATA; + +/** + * struct OBJECT_ID_ATTR - Attribute: Object id (NTFS 3.0+) (0x40). + * + * NOTE: Always resident. + */ +typedef struct { + GUID object_id; /* Unique id assigned to the + file.*/ + /* The following fields are optional. The attribute value size is 16 + bytes, i.e. sizeof(GUID), if these are not present at all. Note, + the entries can be present but one or more (or all) can be zero + meaning that that particular value(s) is(are) not defined. Note, + when the fields are missing here, it is well possible that they are + to be found within the $Extend/$ObjId system file indexed under the + above object_id. */ + union { + struct { + GUID birth_volume_id; /* Unique id of volume on which + the file was first created.*/ + GUID birth_object_id; /* Unique id of file when it was + first created. */ + GUID domain_id; /* Reserved, zero. */ + } __attribute__((__packed__)); + u8 extended_info[48]; + } __attribute__((__packed__)); +} __attribute__((__packed__)) OBJECT_ID_ATTR; + +#if 0 +/** + * enum IDENTIFIER_AUTHORITIES - + * + * The pre-defined IDENTIFIER_AUTHORITIES used as SID_IDENTIFIER_AUTHORITY in + * the SID structure (see below). + */ +typedef enum { /* SID string prefix. */ + SECURITY_NULL_SID_AUTHORITY = {0, 0, 0, 0, 0, 0}, /* S-1-0 */ + SECURITY_WORLD_SID_AUTHORITY = {0, 0, 0, 0, 0, 1}, /* S-1-1 */ + SECURITY_LOCAL_SID_AUTHORITY = {0, 0, 0, 0, 0, 2}, /* S-1-2 */ + SECURITY_CREATOR_SID_AUTHORITY = {0, 0, 0, 0, 0, 3}, /* S-1-3 */ + SECURITY_NON_UNIQUE_AUTHORITY = {0, 0, 0, 0, 0, 4}, /* S-1-4 */ + SECURITY_NT_SID_AUTHORITY = {0, 0, 0, 0, 0, 5}, /* S-1-5 */ +} IDENTIFIER_AUTHORITIES; +#endif + +/** + * enum RELATIVE_IDENTIFIERS - + * + * These relative identifiers (RIDs) are used with the above identifier + * authorities to make up universal well-known SIDs. + * + * Note: The relative identifier (RID) refers to the portion of a SID, which + * identifies a user or group in relation to the authority that issued the SID. + * For example, the universal well-known SID Creator Owner ID (S-1-3-0) is + * made up of the identifier authority SECURITY_CREATOR_SID_AUTHORITY (3) and + * the relative identifier SECURITY_CREATOR_OWNER_RID (0). + */ +typedef enum { /* Identifier authority. */ + SECURITY_NULL_RID = 0, /* S-1-0 */ + SECURITY_WORLD_RID = 0, /* S-1-1 */ + SECURITY_LOCAL_RID = 0, /* S-1-2 */ + + SECURITY_CREATOR_OWNER_RID = 0, /* S-1-3 */ + SECURITY_CREATOR_GROUP_RID = 1, /* S-1-3 */ + + SECURITY_CREATOR_OWNER_SERVER_RID = 2, /* S-1-3 */ + SECURITY_CREATOR_GROUP_SERVER_RID = 3, /* S-1-3 */ + + SECURITY_DIALUP_RID = 1, + SECURITY_NETWORK_RID = 2, + SECURITY_BATCH_RID = 3, + SECURITY_INTERACTIVE_RID = 4, + SECURITY_SERVICE_RID = 6, + SECURITY_ANONYMOUS_LOGON_RID = 7, + SECURITY_PROXY_RID = 8, + SECURITY_ENTERPRISE_CONTROLLERS_RID=9, + SECURITY_SERVER_LOGON_RID = 9, + SECURITY_PRINCIPAL_SELF_RID = 0xa, + SECURITY_AUTHENTICATED_USER_RID = 0xb, + SECURITY_RESTRICTED_CODE_RID = 0xc, + SECURITY_TERMINAL_SERVER_RID = 0xd, + + SECURITY_LOGON_IDS_RID = 5, + SECURITY_LOGON_IDS_RID_COUNT = 3, + + SECURITY_LOCAL_SYSTEM_RID = 0x12, + + SECURITY_NT_NON_UNIQUE = 0x15, + + SECURITY_BUILTIN_DOMAIN_RID = 0x20, + + /* + * Well-known domain relative sub-authority values (RIDs). + */ + + /* Users. */ + DOMAIN_USER_RID_ADMIN = 0x1f4, + DOMAIN_USER_RID_GUEST = 0x1f5, + DOMAIN_USER_RID_KRBTGT = 0x1f6, + + /* Groups. */ + DOMAIN_GROUP_RID_ADMINS = 0x200, + DOMAIN_GROUP_RID_USERS = 0x201, + DOMAIN_GROUP_RID_GUESTS = 0x202, + DOMAIN_GROUP_RID_COMPUTERS = 0x203, + DOMAIN_GROUP_RID_CONTROLLERS = 0x204, + DOMAIN_GROUP_RID_CERT_ADMINS = 0x205, + DOMAIN_GROUP_RID_SCHEMA_ADMINS = 0x206, + DOMAIN_GROUP_RID_ENTERPRISE_ADMINS= 0x207, + DOMAIN_GROUP_RID_POLICY_ADMINS = 0x208, + + /* Aliases. */ + DOMAIN_ALIAS_RID_ADMINS = 0x220, + DOMAIN_ALIAS_RID_USERS = 0x221, + DOMAIN_ALIAS_RID_GUESTS = 0x222, + DOMAIN_ALIAS_RID_POWER_USERS = 0x223, + + DOMAIN_ALIAS_RID_ACCOUNT_OPS = 0x224, + DOMAIN_ALIAS_RID_SYSTEM_OPS = 0x225, + DOMAIN_ALIAS_RID_PRINT_OPS = 0x226, + DOMAIN_ALIAS_RID_BACKUP_OPS = 0x227, + + DOMAIN_ALIAS_RID_REPLICATOR = 0x228, + DOMAIN_ALIAS_RID_RAS_SERVERS = 0x229, + DOMAIN_ALIAS_RID_PREW2KCOMPACCESS = 0x22a, +} RELATIVE_IDENTIFIERS; + +/* + * The universal well-known SIDs: + * + * NULL_SID S-1-0-0 + * WORLD_SID S-1-1-0 + * LOCAL_SID S-1-2-0 + * CREATOR_OWNER_SID S-1-3-0 + * CREATOR_GROUP_SID S-1-3-1 + * CREATOR_OWNER_SERVER_SID S-1-3-2 + * CREATOR_GROUP_SERVER_SID S-1-3-3 + * + * (Non-unique IDs) S-1-4 + * + * NT well-known SIDs: + * + * NT_AUTHORITY_SID S-1-5 + * DIALUP_SID S-1-5-1 + * + * NETWORD_SID S-1-5-2 + * BATCH_SID S-1-5-3 + * INTERACTIVE_SID S-1-5-4 + * SERVICE_SID S-1-5-6 + * ANONYMOUS_LOGON_SID S-1-5-7 (aka null logon session) + * PROXY_SID S-1-5-8 + * SERVER_LOGON_SID S-1-5-9 (aka domain controller account) + * SELF_SID S-1-5-10 (self RID) + * AUTHENTICATED_USER_SID S-1-5-11 + * RESTRICTED_CODE_SID S-1-5-12 (running restricted code) + * TERMINAL_SERVER_SID S-1-5-13 (running on terminal server) + * + * (Logon IDs) S-1-5-5-X-Y + * + * (NT non-unique IDs) S-1-5-0x15-... + * + * (Built-in domain) S-1-5-0x20 + */ + +/** + * union SID_IDENTIFIER_AUTHORITY - A 48-bit value used in the SID structure + * + * NOTE: This is stored as a big endian number. + */ +typedef union { + struct { + u16 high_part; /* High 16-bits. */ + u32 low_part; /* Low 32-bits. */ + } __attribute__((__packed__)); + u8 value[6]; /* Value as individual bytes. */ +} __attribute__((__packed__)) SID_IDENTIFIER_AUTHORITY; + +/** + * struct SID - + * + * The SID structure is a variable-length structure used to uniquely identify + * users or groups. SID stands for security identifier. + * + * The standard textual representation of the SID is of the form: + * S-R-I-S-S... + * Where: + * - The first "S" is the literal character 'S' identifying the following + * digits as a SID. + * - R is the revision level of the SID expressed as a sequence of digits + * in decimal. + * - I is the 48-bit identifier_authority, expressed as digits in decimal, + * if I < 2^32, or hexadecimal prefixed by "0x", if I >= 2^32. + * - S... is one or more sub_authority values, expressed as digits in + * decimal. + * + * Example SID; the domain-relative SID of the local Administrators group on + * Windows NT/2k: + * S-1-5-32-544 + * This translates to a SID with: + * revision = 1, + * sub_authority_count = 2, + * identifier_authority = {0,0,0,0,0,5}, // SECURITY_NT_AUTHORITY + * sub_authority[0] = 32, // SECURITY_BUILTIN_DOMAIN_RID + * sub_authority[1] = 544 // DOMAIN_ALIAS_RID_ADMINS + */ +typedef struct { + u8 revision; + u8 sub_authority_count; + SID_IDENTIFIER_AUTHORITY identifier_authority; + u32 sub_authority[1]; /* At least one sub_authority. */ +} __attribute__((__packed__)) SID; + +/** + * enum SID_CONSTANTS - Current constants for SIDs. + */ +typedef enum { + SID_REVISION = 1, /* Current revision level. */ + SID_MAX_SUB_AUTHORITIES = 15, /* Maximum number of those. */ + SID_RECOMMENDED_SUB_AUTHORITIES = 1, /* Will change to around 6 in + a future revision. */ +} SID_CONSTANTS; + +/** + * enum ACE_TYPES - The predefined ACE types (8-bit, see below). + */ +typedef enum { + ACCESS_MIN_MS_ACE_TYPE = 0, + ACCESS_ALLOWED_ACE_TYPE = 0, + ACCESS_DENIED_ACE_TYPE = 1, + SYSTEM_AUDIT_ACE_TYPE = 2, + SYSTEM_ALARM_ACE_TYPE = 3, /* Not implemented as of Win2k. */ + ACCESS_MAX_MS_V2_ACE_TYPE = 3, + + ACCESS_ALLOWED_COMPOUND_ACE_TYPE= 4, + ACCESS_MAX_MS_V3_ACE_TYPE = 4, + + /* The following are Win2k only. */ + ACCESS_MIN_MS_OBJECT_ACE_TYPE = 5, + ACCESS_ALLOWED_OBJECT_ACE_TYPE = 5, + ACCESS_DENIED_OBJECT_ACE_TYPE = 6, + SYSTEM_AUDIT_OBJECT_ACE_TYPE = 7, + SYSTEM_ALARM_OBJECT_ACE_TYPE = 8, + ACCESS_MAX_MS_OBJECT_ACE_TYPE = 8, + + ACCESS_MAX_MS_V4_ACE_TYPE = 8, + + /* This one is for WinNT&2k. */ + ACCESS_MAX_MS_ACE_TYPE = 8, +} __attribute__((__packed__)) ACE_TYPES; + +/** + * enum ACE_FLAGS - The ACE flags (8-bit) for audit and inheritance. + * + * SUCCESSFUL_ACCESS_ACE_FLAG is only used with system audit and alarm ACE + * types to indicate that a message is generated (in Windows!) for successful + * accesses. + * + * FAILED_ACCESS_ACE_FLAG is only used with system audit and alarm ACE types + * to indicate that a message is generated (in Windows!) for failed accesses. + */ +typedef enum { + /* The inheritance flags. */ + OBJECT_INHERIT_ACE = 0x01, + CONTAINER_INHERIT_ACE = 0x02, + NO_PROPAGATE_INHERIT_ACE = 0x04, + INHERIT_ONLY_ACE = 0x08, + INHERITED_ACE = 0x10, /* Win2k only. */ + VALID_INHERIT_FLAGS = 0x1f, + + /* The audit flags. */ + SUCCESSFUL_ACCESS_ACE_FLAG = 0x40, + FAILED_ACCESS_ACE_FLAG = 0x80, +} __attribute__((__packed__)) ACE_FLAGS; + +/** + * struct ACE_HEADER - + * + * An ACE is an access-control entry in an access-control list (ACL). + * An ACE defines access to an object for a specific user or group or defines + * the types of access that generate system-administration messages or alarms + * for a specific user or group. The user or group is identified by a security + * identifier (SID). + * + * Each ACE starts with an ACE_HEADER structure (aligned on 4-byte boundary), + * which specifies the type and size of the ACE. The format of the subsequent + * data depends on the ACE type. + */ +typedef struct { + ACE_TYPES type; /* Type of the ACE. */ + ACE_FLAGS flags; /* Flags describing the ACE. */ + u16 size; /* Size in bytes of the ACE. */ +} __attribute__((__packed__)) ACE_HEADER; + +/** + * enum ACCESS_MASK - The access mask (32-bit). + * + * Defines the access rights. + */ +typedef enum { + /* + * The specific rights (bits 0 to 15). Depend on the type of the + * object being secured by the ACE. + */ + + /* Specific rights for files and directories are as follows: */ + + /* Right to read data from the file. (FILE) */ + FILE_READ_DATA = const_cpu_to_le32(0x00000001), + /* Right to list contents of a directory. (DIRECTORY) */ + FILE_LIST_DIRECTORY = const_cpu_to_le32(0x00000001), + + /* Right to write data to the file. (FILE) */ + FILE_WRITE_DATA = const_cpu_to_le32(0x00000002), + /* Right to create a file in the directory. (DIRECTORY) */ + FILE_ADD_FILE = const_cpu_to_le32(0x00000002), + + /* Right to append data to the file. (FILE) */ + FILE_APPEND_DATA = const_cpu_to_le32(0x00000004), + /* Right to create a subdirectory. (DIRECTORY) */ + FILE_ADD_SUBDIRECTORY = const_cpu_to_le32(0x00000004), + + /* Right to read extended attributes. (FILE/DIRECTORY) */ + FILE_READ_EA = const_cpu_to_le32(0x00000008), + + /* Right to write extended attributes. (FILE/DIRECTORY) */ + FILE_WRITE_EA = const_cpu_to_le32(0x00000010), + + /* Right to execute a file. (FILE) */ + FILE_EXECUTE = const_cpu_to_le32(0x00000020), + /* Right to traverse the directory. (DIRECTORY) */ + FILE_TRAVERSE = const_cpu_to_le32(0x00000020), + + /* + * Right to delete a directory and all the files it contains (its + * children), even if the files are read-only. (DIRECTORY) + */ + FILE_DELETE_CHILD = const_cpu_to_le32(0x00000040), + + /* Right to read file attributes. (FILE/DIRECTORY) */ + FILE_READ_ATTRIBUTES = const_cpu_to_le32(0x00000080), + + /* Right to change file attributes. (FILE/DIRECTORY) */ + FILE_WRITE_ATTRIBUTES = const_cpu_to_le32(0x00000100), + + /* + * The standard rights (bits 16 to 23). Are independent of the type of + * object being secured. + */ + + /* Right to delete the object. */ + DELETE = const_cpu_to_le32(0x00010000), + + /* + * Right to read the information in the object's security descriptor, + * not including the information in the SACL. I.e. right to read the + * security descriptor and owner. + */ + READ_CONTROL = const_cpu_to_le32(0x00020000), + + /* Right to modify the DACL in the object's security descriptor. */ + WRITE_DAC = const_cpu_to_le32(0x00040000), + + /* Right to change the owner in the object's security descriptor. */ + WRITE_OWNER = const_cpu_to_le32(0x00080000), + + /* + * Right to use the object for synchronization. Enables a process to + * wait until the object is in the signalled state. Some object types + * do not support this access right. + */ + SYNCHRONIZE = const_cpu_to_le32(0x00100000), + + /* + * The following STANDARD_RIGHTS_* are combinations of the above for + * convenience and are defined by the Win32 API. + */ + + /* These are currently defined to READ_CONTROL. */ + STANDARD_RIGHTS_READ = const_cpu_to_le32(0x00020000), + STANDARD_RIGHTS_WRITE = const_cpu_to_le32(0x00020000), + STANDARD_RIGHTS_EXECUTE = const_cpu_to_le32(0x00020000), + + /* Combines DELETE, READ_CONTROL, WRITE_DAC, and WRITE_OWNER access. */ + STANDARD_RIGHTS_REQUIRED = const_cpu_to_le32(0x000f0000), + + /* + * Combines DELETE, READ_CONTROL, WRITE_DAC, WRITE_OWNER, and + * SYNCHRONIZE access. + */ + STANDARD_RIGHTS_ALL = const_cpu_to_le32(0x001f0000), + + /* + * The access system ACL and maximum allowed access types (bits 24 to + * 25, bits 26 to 27 are reserved). + */ + ACCESS_SYSTEM_SECURITY = const_cpu_to_le32(0x01000000), + MAXIMUM_ALLOWED = const_cpu_to_le32(0x02000000), + + /* + * The generic rights (bits 28 to 31). These map onto the standard and + * specific rights. + */ + + /* Read, write, and execute access. */ + GENERIC_ALL = const_cpu_to_le32(0x10000000), + + /* Execute access. */ + GENERIC_EXECUTE = const_cpu_to_le32(0x20000000), + + /* + * Write access. For files, this maps onto: + * FILE_APPEND_DATA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_DATA | + * FILE_WRITE_EA | STANDARD_RIGHTS_WRITE | SYNCHRONIZE + * For directories, the mapping has the same numerical value. See + * above for the descriptions of the rights granted. + */ + GENERIC_WRITE = const_cpu_to_le32(0x40000000), + + /* + * Read access. For files, this maps onto: + * FILE_READ_ATTRIBUTES | FILE_READ_DATA | FILE_READ_EA | + * STANDARD_RIGHTS_READ | SYNCHRONIZE + * For directories, the mapping has the same numerical value. See + * above for the descriptions of the rights granted. + */ + GENERIC_READ = const_cpu_to_le32(0x80000000), +} ACCESS_MASK; + +/** + * struct GENERIC_MAPPING - + * + * The generic mapping array. Used to denote the mapping of each generic + * access right to a specific access mask. + * + * FIXME: What exactly is this and what is it for? (AIA) + */ +typedef struct { + ACCESS_MASK generic_read; + ACCESS_MASK generic_write; + ACCESS_MASK generic_execute; + ACCESS_MASK generic_all; +} __attribute__((__packed__)) GENERIC_MAPPING; + +/* + * The predefined ACE type structures are as defined below. + */ + +/** + * struct ACCESS_DENIED_ACE - + * + * ACCESS_ALLOWED_ACE, ACCESS_DENIED_ACE, SYSTEM_AUDIT_ACE, SYSTEM_ALARM_ACE + */ +typedef struct { +/* 0 ACE_HEADER; -- Unfolded here as gcc doesn't like unnamed structs. */ + ACE_TYPES type; /* Type of the ACE. */ + ACE_FLAGS flags; /* Flags describing the ACE. */ + u16 size; /* Size in bytes of the ACE. */ + +/* 4*/ ACCESS_MASK mask; /* Access mask associated with the ACE. */ +/* 8*/ SID sid; /* The SID associated with the ACE. */ +} __attribute__((__packed__)) ACCESS_ALLOWED_ACE, ACCESS_DENIED_ACE, + SYSTEM_AUDIT_ACE, SYSTEM_ALARM_ACE; + +/** + * enum OBJECT_ACE_FLAGS - The object ACE flags (32-bit). + */ +typedef enum { + ACE_OBJECT_TYPE_PRESENT = const_cpu_to_le32(1), + ACE_INHERITED_OBJECT_TYPE_PRESENT = const_cpu_to_le32(2), +} OBJECT_ACE_FLAGS; + +/** + * struct ACCESS_ALLOWED_OBJECT_ACE - + */ +typedef struct { +/* 0 ACE_HEADER; -- Unfolded here as gcc doesn't like unnamed structs. */ + ACE_TYPES type; /* Type of the ACE. */ + ACE_FLAGS flags; /* Flags describing the ACE. */ + u16 size; /* Size in bytes of the ACE. */ + +/* 4*/ ACCESS_MASK mask; /* Access mask associated with the ACE. */ +/* 8*/ OBJECT_ACE_FLAGS object_flags; /* Flags describing the object ACE. */ +/* 12*/ GUID object_type; +/* 28*/ GUID inherited_object_type; +/* 44*/ SID sid; /* The SID associated with the ACE. */ +} __attribute__((__packed__)) ACCESS_ALLOWED_OBJECT_ACE, + ACCESS_DENIED_OBJECT_ACE, + SYSTEM_AUDIT_OBJECT_ACE, + SYSTEM_ALARM_OBJECT_ACE; + +/** + * struct ACL - An ACL is an access-control list (ACL). + * + * An ACL starts with an ACL header structure, which specifies the size of + * the ACL and the number of ACEs it contains. The ACL header is followed by + * zero or more access control entries (ACEs). The ACL as well as each ACE + * are aligned on 4-byte boundaries. + */ +typedef struct { + u8 revision; /* Revision of this ACL. */ + u8 alignment1; + u16 size; /* Allocated space in bytes for ACL. Includes this + header, the ACEs and the remaining free space. */ + u16 ace_count; /* Number of ACEs in the ACL. */ + u16 alignment2; +/* sizeof() = 8 bytes */ +} __attribute__((__packed__)) ACL; + +/** + * enum ACL_CONSTANTS - Current constants for ACLs. + */ +typedef enum { + /* Current revision. */ + ACL_REVISION = 2, + ACL_REVISION_DS = 4, + + /* History of revisions. */ + ACL_REVISION1 = 1, + MIN_ACL_REVISION = 2, + ACL_REVISION2 = 2, + ACL_REVISION3 = 3, + ACL_REVISION4 = 4, + MAX_ACL_REVISION = 4, +} ACL_CONSTANTS; + +/** + * enum SECURITY_DESCRIPTOR_CONTROL - + * + * The security descriptor control flags (16-bit). + * + * SE_OWNER_DEFAULTED - This boolean flag, when set, indicates that the + * SID pointed to by the Owner field was provided by a + * defaulting mechanism rather than explicitly provided by the + * original provider of the security descriptor. This may + * affect the treatment of the SID with respect to inheritance + * of an owner. + * + * SE_GROUP_DEFAULTED - This boolean flag, when set, indicates that the + * SID in the Group field was provided by a defaulting mechanism + * rather than explicitly provided by the original provider of + * the security descriptor. This may affect the treatment of + * the SID with respect to inheritance of a primary group. + * + * SE_DACL_PRESENT - This boolean flag, when set, indicates that the + * security descriptor contains a discretionary ACL. If this + * flag is set and the Dacl field of the SECURITY_DESCRIPTOR is + * null, then a null ACL is explicitly being specified. + * + * SE_DACL_DEFAULTED - This boolean flag, when set, indicates that the + * ACL pointed to by the Dacl field was provided by a defaulting + * mechanism rather than explicitly provided by the original + * provider of the security descriptor. This may affect the + * treatment of the ACL with respect to inheritance of an ACL. + * This flag is ignored if the DaclPresent flag is not set. + * + * SE_SACL_PRESENT - This boolean flag, when set, indicates that the + * security descriptor contains a system ACL pointed to by the + * Sacl field. If this flag is set and the Sacl field of the + * SECURITY_DESCRIPTOR is null, then an empty (but present) + * ACL is being specified. + * + * SE_SACL_DEFAULTED - This boolean flag, when set, indicates that the + * ACL pointed to by the Sacl field was provided by a defaulting + * mechanism rather than explicitly provided by the original + * provider of the security descriptor. This may affect the + * treatment of the ACL with respect to inheritance of an ACL. + * This flag is ignored if the SaclPresent flag is not set. + * + * SE_SELF_RELATIVE - This boolean flag, when set, indicates that the + * security descriptor is in self-relative form. In this form, + * all fields of the security descriptor are contiguous in memory + * and all pointer fields are expressed as offsets from the + * beginning of the security descriptor. + */ +typedef enum { + SE_OWNER_DEFAULTED = const_cpu_to_le16(0x0001), + SE_GROUP_DEFAULTED = const_cpu_to_le16(0x0002), + SE_DACL_PRESENT = const_cpu_to_le16(0x0004), + SE_DACL_DEFAULTED = const_cpu_to_le16(0x0008), + SE_SACL_PRESENT = const_cpu_to_le16(0x0010), + SE_SACL_DEFAULTED = const_cpu_to_le16(0x0020), + SE_DACL_AUTO_INHERIT_REQ = const_cpu_to_le16(0x0100), + SE_SACL_AUTO_INHERIT_REQ = const_cpu_to_le16(0x0200), + SE_DACL_AUTO_INHERITED = const_cpu_to_le16(0x0400), + SE_SACL_AUTO_INHERITED = const_cpu_to_le16(0x0800), + SE_DACL_PROTECTED = const_cpu_to_le16(0x1000), + SE_SACL_PROTECTED = const_cpu_to_le16(0x2000), + SE_RM_CONTROL_VALID = const_cpu_to_le16(0x4000), + SE_SELF_RELATIVE = const_cpu_to_le16(0x8000), +} __attribute__((__packed__)) SECURITY_DESCRIPTOR_CONTROL; + +/** + * struct SECURITY_DESCRIPTOR_RELATIVE - + * + * Self-relative security descriptor. Contains the owner and group SIDs as well + * as the sacl and dacl ACLs inside the security descriptor itself. + */ +typedef struct { + u8 revision; /* Revision level of the security descriptor. */ + u8 alignment; + SECURITY_DESCRIPTOR_CONTROL control; /* Flags qualifying the type of + the descriptor as well as the following fields. */ + u32 owner; /* Byte offset to a SID representing an object's + owner. If this is NULL, no owner SID is present in + the descriptor. */ + u32 group; /* Byte offset to a SID representing an object's + primary group. If this is NULL, no primary group + SID is present in the descriptor. */ + u32 sacl; /* Byte offset to a system ACL. Only valid, if + SE_SACL_PRESENT is set in the control field. If + SE_SACL_PRESENT is set but sacl is NULL, a NULL ACL + is specified. */ + u32 dacl; /* Byte offset to a discretionary ACL. Only valid, if + SE_DACL_PRESENT is set in the control field. If + SE_DACL_PRESENT is set but dacl is NULL, a NULL ACL + (unconditionally granting access) is specified. */ +/* sizeof() = 0x14 bytes */ +} __attribute__((__packed__)) SECURITY_DESCRIPTOR_RELATIVE; + +/** + * struct SECURITY_DESCRIPTOR - Absolute security descriptor. + * + * Does not contain the owner and group SIDs, nor the sacl and dacl ACLs inside + * the security descriptor. Instead, it contains pointers to these structures + * in memory. Obviously, absolute security descriptors are only useful for in + * memory representations of security descriptors. + * + * On disk, a self-relative security descriptor is used. + */ +typedef struct { + u8 revision; /* Revision level of the security descriptor. */ + u8 alignment; + SECURITY_DESCRIPTOR_CONTROL control; /* Flags qualifying the type of + the descriptor as well as the following fields. */ + SID *owner; /* Points to a SID representing an object's owner. If + this is NULL, no owner SID is present in the + descriptor. */ + SID *group; /* Points to a SID representing an object's primary + group. If this is NULL, no primary group SID is + present in the descriptor. */ + ACL *sacl; /* Points to a system ACL. Only valid, if + SE_SACL_PRESENT is set in the control field. If + SE_SACL_PRESENT is set but sacl is NULL, a NULL ACL + is specified. */ + ACL *dacl; /* Points to a discretionary ACL. Only valid, if + SE_DACL_PRESENT is set in the control field. If + SE_DACL_PRESENT is set but dacl is NULL, a NULL ACL + (unconditionally granting access) is specified. */ +} __attribute__((__packed__)) SECURITY_DESCRIPTOR; + +/** + * enum SECURITY_DESCRIPTOR_CONSTANTS - + * + * Current constants for security descriptors. + */ +typedef enum { + /* Current revision. */ + SECURITY_DESCRIPTOR_REVISION = 1, + SECURITY_DESCRIPTOR_REVISION1 = 1, + + /* The sizes of both the absolute and relative security descriptors is + the same as pointers, at least on ia32 architecture are 32-bit. */ + SECURITY_DESCRIPTOR_MIN_LENGTH = sizeof(SECURITY_DESCRIPTOR), +} SECURITY_DESCRIPTOR_CONSTANTS; + +/* + * Attribute: Security descriptor (0x50). + * + * A standard self-relative security descriptor. + * + * NOTE: Can be resident or non-resident. + * NOTE: Not used in NTFS 3.0+, as security descriptors are stored centrally + * in FILE_Secure and the correct descriptor is found using the security_id + * from the standard information attribute. + */ +typedef SECURITY_DESCRIPTOR_RELATIVE SECURITY_DESCRIPTOR_ATTR; + +/* + * On NTFS 3.0+, all security descriptors are stored in FILE_Secure. Only one + * referenced instance of each unique security descriptor is stored. + * + * FILE_Secure contains no unnamed data attribute, i.e. it has zero length. It + * does, however, contain two indexes ($SDH and $SII) as well as a named data + * stream ($SDS). + * + * Every unique security descriptor is assigned a unique security identifier + * (security_id, not to be confused with a SID). The security_id is unique for + * the NTFS volume and is used as an index into the $SII index, which maps + * security_ids to the security descriptor's storage location within the $SDS + * data attribute. The $SII index is sorted by ascending security_id. + * + * A simple hash is computed from each security descriptor. This hash is used + * as an index into the $SDH index, which maps security descriptor hashes to + * the security descriptor's storage location within the $SDS data attribute. + * The $SDH index is sorted by security descriptor hash and is stored in a B+ + * tree. When searching $SDH (with the intent of determining whether or not a + * new security descriptor is already present in the $SDS data stream), if a + * matching hash is found, but the security descriptors do not match, the + * search in the $SDH index is continued, searching for a next matching hash. + * + * When a precise match is found, the security_id corresponding to the security + * descriptor in the $SDS attribute is read from the found $SDH index entry and + * is stored in the $STANDARD_INFORMATION attribute of the file/directory to + * which the security descriptor is being applied. The $STANDARD_INFORMATION + * attribute is present in all base mft records (i.e. in all files and + * directories). + * + * If a match is not found, the security descriptor is assigned a new unique + * security_id and is added to the $SDS data attribute. Then, entries + * referencing the this security descriptor in the $SDS data attribute are + * added to the $SDH and $SII indexes. + * + * Note: Entries are never deleted from FILE_Secure, even if nothing + * references an entry any more. + */ + +/** + * struct SECURITY_DESCRIPTOR_HEADER - + * + * This header precedes each security descriptor in the $SDS data stream. + * This is also the index entry data part of both the $SII and $SDH indexes. + */ +typedef struct { + u32 hash; /* Hash of the security descriptor. */ + u32 security_id; /* The security_id assigned to the descriptor. */ + u64 offset; /* Byte offset of this entry in the $SDS stream. */ + u32 length; /* Size in bytes of this entry in $SDS stream. */ +} __attribute__((__packed__)) SECURITY_DESCRIPTOR_HEADER; + +/** + * struct SDH_INDEX_DATA - + */ +typedef struct { + u32 hash; /* Hash of the security descriptor. */ + u32 security_id; /* The security_id assigned to the descriptor. */ + u64 offset; /* Byte offset of this entry in the $SDS stream. */ + u32 length; /* Size in bytes of this entry in $SDS stream. */ + u32 reserved_II; /* Padding - always unicode "II" or zero. This field + isn't counted in INDEX_ENTRY's data_length. */ +} __attribute__((__packed__)) SDH_INDEX_DATA; + +/** + * struct SII_INDEX_DATA - + */ +typedef SECURITY_DESCRIPTOR_HEADER SII_INDEX_DATA; + +/** + * struct SDS_ENTRY - + * + * The $SDS data stream contains the security descriptors, aligned on 16-byte + * boundaries, sorted by security_id in a B+ tree. Security descriptors cannot + * cross 256kib boundaries (this restriction is imposed by the Windows cache + * manager). Each security descriptor is contained in a SDS_ENTRY structure. + * Also, each security descriptor is stored twice in the $SDS stream with a + * fixed offset of 0x40000 bytes (256kib, the Windows cache manager's max size) + * between them; i.e. if a SDS_ENTRY specifies an offset of 0x51d0, then the + * the first copy of the security descriptor will be at offset 0x51d0 in the + * $SDS data stream and the second copy will be at offset 0x451d0. + */ +typedef struct { +/* 0 SECURITY_DESCRIPTOR_HEADER; -- Unfolded here as gcc doesn't like + unnamed structs. */ + u32 hash; /* Hash of the security descriptor. */ + u32 security_id; /* The security_id assigned to the descriptor. */ + u64 offset; /* Byte offset of this entry in the $SDS stream. */ + u32 length; /* Size in bytes of this entry in $SDS stream. */ +/* 20*/ SECURITY_DESCRIPTOR_RELATIVE sid; /* The self-relative security + descriptor. */ +} __attribute__((__packed__)) SDS_ENTRY; + +/** + * struct SII_INDEX_KEY - The index entry key used in the $SII index. + * + * The collation type is COLLATION_NTOFS_ULONG. + */ +typedef struct { + u32 security_id; /* The security_id assigned to the descriptor. */ +} __attribute__((__packed__)) SII_INDEX_KEY; + +/** + * struct SDH_INDEX_KEY - The index entry key used in the $SDH index. + * + * The keys are sorted first by hash and then by security_id. + * The collation rule is COLLATION_NTOFS_SECURITY_HASH. + */ +typedef struct { + u32 hash; /* Hash of the security descriptor. */ + u32 security_id; /* The security_id assigned to the descriptor. */ +} __attribute__((__packed__)) SDH_INDEX_KEY; + +/** + * struct VOLUME_NAME - Attribute: Volume name (0x60). + * + * NOTE: Always resident. + * NOTE: Present only in FILE_Volume. + */ +typedef struct { + ntfschar name[0]; /* The name of the volume in Unicode. */ +} __attribute__((__packed__)) VOLUME_NAME; + +/** + * enum VOLUME_FLAGS - Possible flags for the volume (16-bit). + */ +typedef enum { + VOLUME_IS_DIRTY = const_cpu_to_le16(0x0001), + VOLUME_RESIZE_LOG_FILE = const_cpu_to_le16(0x0002), + VOLUME_UPGRADE_ON_MOUNT = const_cpu_to_le16(0x0004), + VOLUME_MOUNTED_ON_NT4 = const_cpu_to_le16(0x0008), + VOLUME_DELETE_USN_UNDERWAY = const_cpu_to_le16(0x0010), + VOLUME_REPAIR_OBJECT_ID = const_cpu_to_le16(0x0020), + VOLUME_CHKDSK_UNDERWAY = const_cpu_to_le16(0x4000), + VOLUME_MODIFIED_BY_CHKDSK = const_cpu_to_le16(0x8000), + VOLUME_FLAGS_MASK = const_cpu_to_le16(0xc03f), +} __attribute__((__packed__)) VOLUME_FLAGS; + +/** + * struct VOLUME_INFORMATION - Attribute: Volume information (0x70). + * + * NOTE: Always resident. + * NOTE: Present only in FILE_Volume. + * NOTE: Windows 2000 uses NTFS 3.0 while Windows NT4 service pack 6a uses + * NTFS 1.2. I haven't personally seen other values yet. + */ +typedef struct { + u64 reserved; /* Not used (yet?). */ + u8 major_ver; /* Major version of the ntfs format. */ + u8 minor_ver; /* Minor version of the ntfs format. */ + VOLUME_FLAGS flags; /* Bit array of VOLUME_* flags. */ +} __attribute__((__packed__)) VOLUME_INFORMATION; + +/** + * struct DATA_ATTR - Attribute: Data attribute (0x80). + * + * NOTE: Can be resident or non-resident. + * + * Data contents of a file (i.e. the unnamed stream) or of a named stream. + */ +typedef struct { + u8 data[0]; /* The file's data contents. */ +} __attribute__((__packed__)) DATA_ATTR; + +/** + * enum INDEX_HEADER_FLAGS - Index header flags (8-bit). + */ +typedef enum { + /* When index header is in an index root attribute: */ + SMALL_INDEX = 0, /* The index is small enough to fit inside the + index root attribute and there is no index + allocation attribute present. */ + LARGE_INDEX = 1, /* The index is too large to fit in the index + root attribute and/or an index allocation + attribute is present. */ + /* + * When index header is in an index block, i.e. is part of index + * allocation attribute: + */ + LEAF_NODE = 0, /* This is a leaf node, i.e. there are no more + nodes branching off it. */ + INDEX_NODE = 1, /* This node indexes other nodes, i.e. is not a + leaf node. */ + NODE_MASK = 1, /* Mask for accessing the *_NODE bits. */ +} __attribute__((__packed__)) INDEX_HEADER_FLAGS; + +/** + * struct INDEX_HEADER - + * + * This is the header for indexes, describing the INDEX_ENTRY records, which + * follow the INDEX_HEADER. Together the index header and the index entries + * make up a complete index. + * + * IMPORTANT NOTE: The offset, length and size structure members are counted + * relative to the start of the index header structure and not relative to the + * start of the index root or index allocation structures themselves. + */ +typedef struct { +/* 0*/ u32 entries_offset; /* Byte offset from the INDEX_HEADER to first + INDEX_ENTRY, aligned to 8-byte boundary. */ +/* 4*/ u32 index_length; /* Data size in byte of the INDEX_ENTRY's, + including the INDEX_HEADER, aligned to 8. */ +/* 8*/ u32 allocated_size; /* Allocated byte size of this index (block), + multiple of 8 bytes. See more below. */ + /* + For the index root attribute, the above two numbers are always + equal, as the attribute is resident and it is resized as needed. + + For the index allocation attribute, the attribute is not resident + and the allocated_size is equal to the index_block_size specified + by the corresponding INDEX_ROOT attribute minus the INDEX_BLOCK + size not counting the INDEX_HEADER part (i.e. minus -24). + */ +/* 12*/ INDEX_HEADER_FLAGS ih_flags; /* Bit field of INDEX_HEADER_FLAGS. */ +/* 13*/ u8 reserved[3]; /* Reserved/align to 8-byte boundary.*/ +/* sizeof() == 16 */ +} __attribute__((__packed__)) INDEX_HEADER; + +/** + * struct INDEX_ROOT - Attribute: Index root (0x90). + * + * NOTE: Always resident. + * + * This is followed by a sequence of index entries (INDEX_ENTRY structures) + * as described by the index header. + * + * When a directory is small enough to fit inside the index root then this + * is the only attribute describing the directory. When the directory is too + * large to fit in the index root, on the other hand, two additional attributes + * are present: an index allocation attribute, containing sub-nodes of the B+ + * directory tree (see below), and a bitmap attribute, describing which virtual + * cluster numbers (vcns) in the index allocation attribute are in use by an + * index block. + * + * NOTE: The root directory (FILE_root) contains an entry for itself. Other + * directories do not contain entries for themselves, though. + */ +typedef struct { +/* 0*/ ATTR_TYPES type; /* Type of the indexed attribute. Is + $FILE_NAME for directories, zero + for view indexes. No other values + allowed. */ +/* 4*/ COLLATION_RULES collation_rule; /* Collation rule used to sort the + index entries. If type is $FILE_NAME, + this must be COLLATION_FILE_NAME. */ +/* 8*/ u32 index_block_size; /* Size of index block in bytes (in + the index allocation attribute). */ +/* 12*/ s8 clusters_per_index_block; /* Size of index block in clusters (in + the index allocation attribute), when + an index block is >= than a cluster, + otherwise sectors per index block. */ +/* 13*/ u8 reserved[3]; /* Reserved/align to 8-byte boundary. */ +/* 16*/ INDEX_HEADER index; /* Index header describing the + following index entries. */ +/* sizeof()= 32 bytes */ +} __attribute__((__packed__)) INDEX_ROOT; + +/** + * struct INDEX_BLOCK - Attribute: Index allocation (0xa0). + * + * NOTE: Always non-resident (doesn't make sense to be resident anyway!). + * + * This is an array of index blocks. Each index block starts with an + * INDEX_BLOCK structure containing an index header, followed by a sequence of + * index entries (INDEX_ENTRY structures), as described by the INDEX_HEADER. + */ +typedef struct { +/* 0 NTFS_RECORD; -- Unfolded here as gcc doesn't like unnamed structs. */ + NTFS_RECORD_TYPES magic;/* Magic is "INDX". */ + u16 usa_ofs; /* See NTFS_RECORD definition. */ + u16 usa_count; /* See NTFS_RECORD definition. */ + +/* 8*/ LSN lsn; /* $LogFile sequence number of the last + modification of this index block. */ +/* 16*/ VCN index_block_vcn; /* Virtual cluster number of the index block. */ +/* 24*/ INDEX_HEADER index; /* Describes the following index entries. */ +/* sizeof()= 40 (0x28) bytes */ +/* + * When creating the index block, we place the update sequence array at this + * offset, i.e. before we start with the index entries. This also makes sense, + * otherwise we could run into problems with the update sequence array + * containing in itself the last two bytes of a sector which would mean that + * multi sector transfer protection wouldn't work. As you can't protect data + * by overwriting it since you then can't get it back... + * When reading use the data from the ntfs record header. + */ +} __attribute__((__packed__)) INDEX_BLOCK; + +typedef INDEX_BLOCK INDEX_ALLOCATION; + +/** + * struct REPARSE_INDEX_KEY - + * + * The system file FILE_Extend/$Reparse contains an index named $R listing + * all reparse points on the volume. The index entry keys are as defined + * below. Note, that there is no index data associated with the index entries. + * + * The index entries are sorted by the index key file_id. The collation rule is + * COLLATION_NTOFS_ULONGS. FIXME: Verify whether the reparse_tag is not the + * primary key / is not a key at all. (AIA) + */ +typedef struct { + u32 reparse_tag; /* Reparse point type (inc. flags). */ + MFT_REF file_id; /* Mft record of the file containing the + reparse point attribute. */ +} __attribute__((__packed__)) REPARSE_INDEX_KEY; + +/** + * enum QUOTA_FLAGS - Quota flags (32-bit). + */ +typedef enum { + /* The user quota flags. Names explain meaning. */ + QUOTA_FLAG_DEFAULT_LIMITS = const_cpu_to_le32(0x00000001), + QUOTA_FLAG_LIMIT_REACHED = const_cpu_to_le32(0x00000002), + QUOTA_FLAG_ID_DELETED = const_cpu_to_le32(0x00000004), + + QUOTA_FLAG_USER_MASK = const_cpu_to_le32(0x00000007), + /* Bit mask for user quota flags. */ + + /* These flags are only present in the quota defaults index entry, + i.e. in the entry where owner_id = QUOTA_DEFAULTS_ID. */ + QUOTA_FLAG_TRACKING_ENABLED = const_cpu_to_le32(0x00000010), + QUOTA_FLAG_ENFORCEMENT_ENABLED = const_cpu_to_le32(0x00000020), + QUOTA_FLAG_TRACKING_REQUESTED = const_cpu_to_le32(0x00000040), + QUOTA_FLAG_LOG_THRESHOLD = const_cpu_to_le32(0x00000080), + QUOTA_FLAG_LOG_LIMIT = const_cpu_to_le32(0x00000100), + QUOTA_FLAG_OUT_OF_DATE = const_cpu_to_le32(0x00000200), + QUOTA_FLAG_CORRUPT = const_cpu_to_le32(0x00000400), + QUOTA_FLAG_PENDING_DELETES = const_cpu_to_le32(0x00000800), +} QUOTA_FLAGS; + +/** + * struct QUOTA_CONTROL_ENTRY - + * + * The system file FILE_Extend/$Quota contains two indexes $O and $Q. Quotas + * are on a per volume and per user basis. + * + * The $Q index contains one entry for each existing user_id on the volume. The + * index key is the user_id of the user/group owning this quota control entry, + * i.e. the key is the owner_id. The user_id of the owner of a file, i.e. the + * owner_id, is found in the standard information attribute. The collation rule + * for $Q is COLLATION_NTOFS_ULONG. + * + * The $O index contains one entry for each user/group who has been assigned + * a quota on that volume. The index key holds the SID of the user_id the + * entry belongs to, i.e. the owner_id. The collation rule for $O is + * COLLATION_NTOFS_SID. + * + * The $O index entry data is the user_id of the user corresponding to the SID. + * This user_id is used as an index into $Q to find the quota control entry + * associated with the SID. + * + * The $Q index entry data is the quota control entry and is defined below. + */ +typedef struct { + u32 version; /* Currently equals 2. */ + QUOTA_FLAGS flags; /* Flags describing this quota entry. */ + u64 bytes_used; /* How many bytes of the quota are in use. */ + s64 change_time; /* Last time this quota entry was changed. */ + s64 threshold; /* Soft quota (-1 if not limited). */ + s64 limit; /* Hard quota (-1 if not limited). */ + s64 exceeded_time; /* How long the soft quota has been exceeded. */ +/* The below field is NOT present for the quota defaults entry. */ + SID sid; /* The SID of the user/object associated with + this quota entry. If this field is missing + then the INDEX_ENTRY is padded with zeros + to multiply of 8 which are not counted in + the data_length field. If the sid is present + then this structure is padded with zeros to + multiply of 8 and the padding is counted in + the INDEX_ENTRY's data_length. */ +} __attribute__((__packed__)) QUOTA_CONTROL_ENTRY; + +/** + * struct QUOTA_O_INDEX_DATA - + */ +typedef struct { + u32 owner_id; + u32 unknown; /* Always 32. Seems to be padding and it's not + counted in the INDEX_ENTRY's data_length. + This field shouldn't be really here. */ +} __attribute__((__packed__)) QUOTA_O_INDEX_DATA; + +/** + * enum PREDEFINED_OWNER_IDS - Predefined owner_id values (32-bit). + */ +typedef enum { + QUOTA_INVALID_ID = const_cpu_to_le32(0x00000000), + QUOTA_DEFAULTS_ID = const_cpu_to_le32(0x00000001), + QUOTA_FIRST_USER_ID = const_cpu_to_le32(0x00000100), +} PREDEFINED_OWNER_IDS; + +/** + * enum INDEX_ENTRY_FLAGS - Index entry flags (16-bit). + */ +typedef enum { + INDEX_ENTRY_NODE = const_cpu_to_le16(1), /* This entry contains a + sub-node, i.e. a reference to an index + block in form of a virtual cluster + number (see below). */ + INDEX_ENTRY_END = const_cpu_to_le16(2), /* This signifies the last + entry in an index block. The index + entry does not represent a file but it + can point to a sub-node. */ + INDEX_ENTRY_SPACE_FILLER = 0xffff, /* Just to force 16-bit width. */ +} __attribute__((__packed__)) INDEX_ENTRY_FLAGS; + +/** + * struct INDEX_ENTRY_HEADER - This the index entry header (see below). + * + * ========================================================== + * !!!!! SEE DESCRIPTION OF THE FIELDS AT INDEX_ENTRY !!!!! + * ========================================================== + */ +typedef struct { +/* 0*/ union { + MFT_REF indexed_file; + struct { + u16 data_offset; + u16 data_length; + u32 reservedV; + } __attribute__((__packed__)); + } __attribute__((__packed__)); +/* 8*/ u16 length; +/* 10*/ u16 key_length; +/* 12*/ INDEX_ENTRY_FLAGS flags; +/* 14*/ u16 reserved; +/* sizeof() = 16 bytes */ +} __attribute__((__packed__)) INDEX_ENTRY_HEADER; + +/** + * struct INDEX_ENTRY - This is an index entry. + * + * A sequence of such entries follows each INDEX_HEADER structure. Together + * they make up a complete index. The index follows either an index root + * attribute or an index allocation attribute. + * + * NOTE: Before NTFS 3.0 only filename attributes were indexed. + */ +typedef struct { +/* 0 INDEX_ENTRY_HEADER; -- Unfolded here as gcc dislikes unnamed structs. */ + union { /* Only valid when INDEX_ENTRY_END is not set. */ + MFT_REF indexed_file; /* The mft reference of the file + described by this index + entry. Used for directory + indexes. */ + struct { /* Used for views/indexes to find the entry's data. */ + u16 data_offset; /* Data byte offset from this + INDEX_ENTRY. Follows the + index key. */ + u16 data_length; /* Data length in bytes. */ + u32 reservedV; /* Reserved (zero). */ + } __attribute__((__packed__)); + } __attribute__((__packed__)); +/* 8*/ u16 length; /* Byte size of this index entry, multiple of + 8-bytes. Size includes INDEX_ENTRY_HEADER + and the optional subnode VCN. See below. */ +/* 10*/ u16 key_length; /* Byte size of the key value, which is in the + index entry. It follows field reserved. Not + multiple of 8-bytes. */ +/* 12*/ INDEX_ENTRY_FLAGS ie_flags; /* Bit field of INDEX_ENTRY_* flags. */ +/* 14*/ u16 reserved; /* Reserved/align to 8-byte boundary. */ +/* End of INDEX_ENTRY_HEADER */ +/* 16*/ union { /* The key of the indexed attribute. NOTE: Only present + if INDEX_ENTRY_END bit in flags is not set. NOTE: On + NTFS versions before 3.0 the only valid key is the + FILE_NAME_ATTR. On NTFS 3.0+ the following + additional index keys are defined: */ + FILE_NAME_ATTR file_name;/* $I30 index in directories. */ + SII_INDEX_KEY sii; /* $SII index in $Secure. */ + SDH_INDEX_KEY sdh; /* $SDH index in $Secure. */ + GUID object_id; /* $O index in FILE_Extend/$ObjId: The + object_id of the mft record found in + the data part of the index. */ + REPARSE_INDEX_KEY reparse; /* $R index in + FILE_Extend/$Reparse. */ + SID sid; /* $O index in FILE_Extend/$Quota: + SID of the owner of the user_id. */ + u32 owner_id; /* $Q index in FILE_Extend/$Quota: + user_id of the owner of the quota + control entry in the data part of + the index. */ + } __attribute__((__packed__)) key; + /* The (optional) index data is inserted here when creating. + VCN vcn; If INDEX_ENTRY_NODE bit in ie_flags is set, the last + eight bytes of this index entry contain the virtual + cluster number of the index block that holds the + entries immediately preceding the current entry. + + If the key_length is zero, then the vcn immediately + follows the INDEX_ENTRY_HEADER. + + The address of the vcn of "ie" INDEX_ENTRY is given by + (char*)ie + le16_to_cpu(ie->length) - sizeof(VCN) + */ +} __attribute__((__packed__)) INDEX_ENTRY; + +/** + * struct BITMAP_ATTR - Attribute: Bitmap (0xb0). + * + * Contains an array of bits (aka a bitfield). + * + * When used in conjunction with the index allocation attribute, each bit + * corresponds to one index block within the index allocation attribute. Thus + * the number of bits in the bitmap * index block size / cluster size is the + * number of clusters in the index allocation attribute. + */ +typedef struct { + u8 bitmap[0]; /* Array of bits. */ +} __attribute__((__packed__)) BITMAP_ATTR; + +/** + * enum PREDEFINED_REPARSE_TAGS - + * + * The reparse point tag defines the type of the reparse point. It also + * includes several flags, which further describe the reparse point. + * + * The reparse point tag is an unsigned 32-bit value divided in three parts: + * + * 1. The least significant 16 bits (i.e. bits 0 to 15) specify the type of + * the reparse point. + * 2. The 13 bits after this (i.e. bits 16 to 28) are reserved for future use. + * 3. The most significant three bits are flags describing the reparse point. + * They are defined as follows: + * bit 29: Name surrogate bit. If set, the filename is an alias for + * another object in the system. + * bit 30: High-latency bit. If set, accessing the first byte of data will + * be slow. (E.g. the data is stored on a tape drive.) + * bit 31: Microsoft bit. If set, the tag is owned by Microsoft. User + * defined tags have to use zero here. + */ +typedef enum { + IO_REPARSE_TAG_IS_ALIAS = const_cpu_to_le32(0x20000000), + IO_REPARSE_TAG_IS_HIGH_LATENCY = const_cpu_to_le32(0x40000000), + IO_REPARSE_TAG_IS_MICROSOFT = const_cpu_to_le32(0x80000000), + + IO_REPARSE_TAG_RESERVED_ZERO = const_cpu_to_le32(0x00000000), + IO_REPARSE_TAG_RESERVED_ONE = const_cpu_to_le32(0x00000001), + IO_REPARSE_TAG_RESERVED_RANGE = const_cpu_to_le32(0x00000001), + + IO_REPARSE_TAG_NSS = const_cpu_to_le32(0x68000005), + IO_REPARSE_TAG_NSS_RECOVER = const_cpu_to_le32(0x68000006), + IO_REPARSE_TAG_SIS = const_cpu_to_le32(0x68000007), + IO_REPARSE_TAG_DFS = const_cpu_to_le32(0x68000008), + + IO_REPARSE_TAG_MOUNT_POINT = const_cpu_to_le32(0x88000003), + + IO_REPARSE_TAG_HSM = const_cpu_to_le32(0xa8000004), + + IO_REPARSE_TAG_SYMBOLIC_LINK = const_cpu_to_le32(0xe8000000), + + IO_REPARSE_TAG_VALID_VALUES = const_cpu_to_le32(0xe000ffff), +} PREDEFINED_REPARSE_TAGS; + +/** + * struct REPARSE_POINT - Attribute: Reparse point (0xc0). + * + * NOTE: Can be resident or non-resident. + */ +typedef struct { + u32 reparse_tag; /* Reparse point type (inc. flags). */ + u16 reparse_data_length; /* Byte size of reparse data. */ + u16 reserved; /* Align to 8-byte boundary. */ + u8 reparse_data[0]; /* Meaning depends on reparse_tag. */ +} __attribute__((__packed__)) REPARSE_POINT; + +/** + * struct EA_INFORMATION - Attribute: Extended attribute information (0xd0). + * + * NOTE: Always resident. + */ +typedef struct { + u16 ea_length; /* Byte size of the packed extended + attributes. */ + u16 need_ea_count; /* The number of extended attributes which have + the NEED_EA bit set. */ + u32 ea_query_length; /* Byte size of the buffer required to query + the extended attributes when calling + ZwQueryEaFile() in Windows NT/2k. I.e. the + byte size of the unpacked extended + attributes. */ +} __attribute__((__packed__)) EA_INFORMATION; + +/** + * enum EA_FLAGS - Extended attribute flags (8-bit). + */ +typedef enum { + NEED_EA = 0x80, /* Indicate that the file to which the EA + belongs cannot be interpreted without + understanding the associated extended + attributes. */ +} __attribute__((__packed__)) EA_FLAGS; + +/** + * struct EA_ATTR - Attribute: Extended attribute (EA) (0xe0). + * + * Like the attribute list and the index buffer list, the EA attribute value is + * a sequence of EA_ATTR variable length records. + * + * FIXME: It appears weird that the EA name is not Unicode. Is it true? + * FIXME: It seems that name is always uppercased. Is it true? + */ +typedef struct { + u32 next_entry_offset; /* Offset to the next EA_ATTR. */ + EA_FLAGS flags; /* Flags describing the EA. */ + u8 name_length; /* Length of the name of the extended + attribute in bytes. */ + u16 value_length; /* Byte size of the EA's value. */ + u8 name[0]; /* Name of the EA. */ + u8 value[0]; /* The value of the EA. Immediately + follows the name. */ +} __attribute__((__packed__)) EA_ATTR; + +/** + * struct PROPERTY_SET - Attribute: Property set (0xf0). + * + * Intended to support Native Structure Storage (NSS) - a feature removed from + * NTFS 3.0 during beta testing. + */ +typedef struct { + /* Irrelevant as feature unused. */ +} __attribute__((__packed__)) PROPERTY_SET; + +/** + * struct LOGGED_UTILITY_STREAM - Attribute: Logged utility stream (0x100). + * + * NOTE: Can be resident or non-resident. + * + * Operations on this attribute are logged to the journal ($LogFile) like + * normal metadata changes. + * + * Used by the Encrypting File System (EFS). All encrypted files have this + * attribute with the name $EFS. See below for the relevant structures. + */ +typedef struct { + /* Can be anything the creator chooses. */ +} __attribute__((__packed__)) LOGGED_UTILITY_STREAM; + +/* + * $EFS Data Structure: + * + * The following information is about the data structures that are contained + * inside a logged utility stream (0x100) with a name of "$EFS". + * + * The stream starts with an instance of EFS_ATTR_HEADER. + * + * Next, at offsets offset_to_ddf_array and offset_to_drf_array (unless any of + * them is 0) there is a EFS_DF_ARRAY_HEADER immediately followed by a sequence + * of multiple data decryption/recovery fields. + * + * Each data decryption/recovery field starts with a EFS_DF_HEADER and the next + * one (if it exists) can be found by adding EFS_DF_HEADER->df_length bytes to + * the offset of the beginning of the current EFS_DF_HEADER. + * + * The data decryption/recovery field contains an EFS_DF_CERTIFICATE_HEADER, a + * SID, an optional GUID, an optional container name, a non-optional user name, + * and the encrypted FEK. + * + * Note all the below are best guesses so may have mistakes/inaccuracies. + * Corrections/clarifications/additions are always welcome! + * + * Ntfs.sys takes an EFS value length of <= 0x54 or > 0x40000 to BSOD, i.e. it + * is invalid. + */ + +/** + * struct EFS_ATTR_HEADER - "$EFS" header. + * + * The header of the Logged utility stream (0x100) attribute named "$EFS". + */ +typedef struct { +/* 0*/ u32 length; /* Length of EFS attribute in bytes. */ + u32 state; /* Always 0? */ + u32 version; /* Efs version. Always 2? */ + u32 crypto_api_version; /* Always 0? */ +/* 16*/ u8 unknown4[16]; /* MD5 hash of decrypted FEK? This field is + created with a call to UuidCreate() so is + unlikely to be an MD5 hash and is more + likely to be GUID of this encrytped file + or something like that. */ +/* 32*/ u8 unknown5[16]; /* MD5 hash of DDFs? */ +/* 48*/ u8 unknown6[16]; /* MD5 hash of DRFs? */ +/* 64*/ u32 offset_to_ddf_array;/* Offset in bytes to the array of data + decryption fields (DDF), see below. Zero if + no DDFs are present. */ + u32 offset_to_drf_array;/* Offset in bytes to the array of data + recovery fields (DRF), see below. Zero if + no DRFs are present. */ + u32 reserved; /* Reserved. */ +} __attribute__((__packed__)) EFS_ATTR_HEADER; + +/** + * struct EFS_DF_ARRAY_HEADER - + */ +typedef struct { + u32 df_count; /* Number of data decryption/recovery fields in + the array. */ +} __attribute__((__packed__)) EFS_DF_ARRAY_HEADER; + +/** + * struct EFS_DF_HEADER - + */ +typedef struct { +/* 0*/ u32 df_length; /* Length of this data decryption/recovery + field in bytes. */ + u32 cred_header_offset; /* Offset in bytes to the credential header. */ + u32 fek_size; /* Size in bytes of the encrypted file + encryption key (FEK). */ + u32 fek_offset; /* Offset in bytes to the FEK from the start of + the data decryption/recovery field. */ +/* 16*/ u32 unknown1; /* always 0? Might be just padding. */ +} __attribute__((__packed__)) EFS_DF_HEADER; + +/** + * struct EFS_DF_CREDENTIAL_HEADER - + */ +typedef struct { +/* 0*/ u32 cred_length; /* Length of this credential in bytes. */ + u32 sid_offset; /* Offset in bytes to the user's sid from start + of this structure. Zero if no sid is + present. */ +/* 8*/ u32 type; /* Type of this credential: + 1 = CryptoAPI container. + 2 = Unexpected type. + 3 = Certificate thumbprint. + other = Unknown type. */ + union { + /* CryptoAPI container. */ + struct { +/* 12*/ u32 container_name_offset; /* Offset in bytes to + the name of the container from start of this + structure (may not be zero). */ +/* 16*/ u32 provider_name_offset; /* Offset in bytes to + the name of the provider from start of this + structure (may not be zero). */ + u32 public_key_blob_offset; /* Offset in bytes to + the public key blob from start of this + structure. */ +/* 24*/ u32 public_key_blob_size; /* Size in bytes of + public key blob. */ + } __attribute__((__packed__)); + /* Certificate thumbprint. */ + struct { +/* 12*/ u32 cert_thumbprint_header_size; /* Size in + bytes of the header of the certificate + thumbprint. */ +/* 16*/ u32 cert_thumbprint_header_offset; /* Offset in + bytes to the header of the certificate + thumbprint from start of this structure. */ + u32 unknown1; /* Always 0? Might be padding... */ + u32 unknown2; /* Always 0? Might be padding... */ + } __attribute__((__packed__)); + } __attribute__((__packed__)); +} __attribute__((__packed__)) EFS_DF_CREDENTIAL_HEADER; + +typedef EFS_DF_CREDENTIAL_HEADER EFS_DF_CRED_HEADER; + +/** + * struct EFS_DF_CERTIFICATE_THUMBPRINT_HEADER - + */ +typedef struct { +/* 0*/ u32 thumbprint_offset; /* Offset in bytes to the thumbprint. */ + u32 thumbprint_size; /* Size of thumbprint in bytes. */ +/* 8*/ u32 container_name_offset; /* Offset in bytes to the name of the + container from start of this + structure or 0 if no name present. */ + u32 provider_name_offset; /* Offset in bytes to the name of the + cryptographic provider from start of + this structure or 0 if no name + present. */ +/* 16*/ u32 user_name_offset; /* Offset in bytes to the user name + from start of this structure or 0 if + no user name present. (This is also + known as lpDisplayInformation.) */ +} __attribute__((__packed__)) EFS_DF_CERTIFICATE_THUMBPRINT_HEADER; + +typedef EFS_DF_CERTIFICATE_THUMBPRINT_HEADER EFS_DF_CERT_THUMBPRINT_HEADER; + +typedef enum { + INTX_SYMBOLIC_LINK = + const_cpu_to_le64(0x014B4E4C78746E49ULL), /* "IntxLNK\1" */ + INTX_CHARACTER_DEVICE = + const_cpu_to_le64(0x0052484378746E49ULL), /* "IntxCHR\0" */ + INTX_BLOCK_DEVICE = + const_cpu_to_le64(0x004B4C4278746E49ULL), /* "IntxBLK\0" */ +} INTX_FILE_TYPES; + +typedef struct { + INTX_FILE_TYPES magic; /* Intx file magic. */ + union { + /* For character and block devices. */ + struct { + u64 major; /* Major device number. */ + u64 minor; /* Minor device number. */ + void *device_end[0]; /* Marker for offsetof(). */ + } __attribute__((__packed__)); + /* For symbolic links. */ + ntfschar target[0]; + } __attribute__((__packed__)); +} __attribute__((__packed__)) INTX_FILE; + +#endif /* defined _NTFS_LAYOUT_H */ diff --git a/include/ntfs-3g/lcnalloc.h b/include/ntfs-3g/lcnalloc.h new file mode 100755 index 0000000..e87ca43 --- a/dev/null +++ b/include/ntfs-3g/lcnalloc.h @@ -0,0 +1,50 @@ +/* + * lcnalloc.h - Exports for cluster (de)allocation. Originated from the Linux-NTFS + * project. + * + * Copyright (c) 2002 Anton Altaparmakov + * Copyright (c) 2004 Yura Pakhuchiy + * + * This program/include file 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/include file 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 (in the main directory of the NTFS-3G + * distribution in the file COPYING); if not, write to the Free Software + * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _NTFS_LCNALLOC_H +#define _NTFS_LCNALLOC_H + +#include "types.h" +#include "runlist.h" +#include "volume.h" + +/** + * enum NTFS_CLUSTER_ALLOCATION_ZONES - + */ +typedef enum { + FIRST_ZONE = 0, /* For sanity checking. */ + MFT_ZONE = 0, /* Allocate from $MFT zone. */ + DATA_ZONE = 1, /* Allocate from $DATA zone. */ + LAST_ZONE = 1, /* For sanity checking. */ +} NTFS_CLUSTER_ALLOCATION_ZONES; + +extern runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count, + LCN start_lcn, const NTFS_CLUSTER_ALLOCATION_ZONES zone); + +extern int ntfs_cluster_free_from_rl(ntfs_volume *vol, runlist *rl); + +extern int ntfs_cluster_free(ntfs_volume *vol, ntfs_attr *na, VCN start_vcn, + s64 count); + +#endif /* defined _NTFS_LCNALLOC_H */ + diff --git a/include/ntfs-3g/logfile.h b/include/ntfs-3g/logfile.h new file mode 100755 index 0000000..798d562 --- a/dev/null +++ b/include/ntfs-3g/logfile.h @@ -0,0 +1,394 @@ +/* + * logfile.h - Exports for $LogFile handling. Originated from the Linux-NTFS project. + * + * Copyright (c) 2000-2005 Anton Altaparmakov + * + * This program/include file 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/include file 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 (in the main directory of the NTFS-3G + * distribution in the file COPYING); if not, write to the Free Software + * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _NTFS_LOGFILE_H +#define _NTFS_LOGFILE_H + +#include "types.h" +#include "endians.h" +#include "layout.h" + +/* + * Journal ($LogFile) organization: + * + * Two restart areas present in the first two pages (restart pages, one restart + * area in each page). When the volume is dismounted they should be identical, + * except for the update sequence array which usually has a different update + * sequence number. + * + * These are followed by log records organized in pages headed by a log record + * header going up to log file size. Not all pages contain log records when a + * volume is first formatted, but as the volume ages, all records will be used. + * When the log file fills up, the records at the beginning are purged (by + * modifying the oldest_lsn to a higher value presumably) and writing begins + * at the beginning of the file. Effectively, the log file is viewed as a + * circular entity. + * + * NOTE: Windows NT, 2000, and XP all use log file version 1.1 but they accept + * versions <= 1.x, including 0.-1. (Yes, that is a minus one in there!) We + * probably only want to support 1.1 as this seems to be the current version + * and we don't know how that differs from the older versions. The only + * exception is if the journal is clean as marked by the two restart pages + * then it doesn't matter whether we are on an earlier version. We can just + * reinitialize the logfile and start again with version 1.1. + */ + +/* Some $LogFile related constants. */ +#define MaxLogFileSize 0x100000000ULL +#define DefaultLogPageSize 4096 +#define MinLogRecordPages 48 + +/** + * struct RESTART_PAGE_HEADER - Log file restart page header. + * + * Begins the restart area. + */ +typedef struct { +/*Ofs*/ +/* 0 NTFS_RECORD; -- Unfolded here as gcc doesn't like unnamed structs. */ +/* 0*/ NTFS_RECORD_TYPES magic;/* The magic is "RSTR". */ +/* 4*/ le16 usa_ofs; /* See NTFS_RECORD definition in layout.h. + When creating, set this to be immediately + after this header structure (without any + alignment). */ +/* 6*/ le16 usa_count; /* See NTFS_RECORD definition in layout.h. */ + +/* 8*/ leLSN chkdsk_lsn; /* The last log file sequence number found by + chkdsk. Only used when the magic is changed + to "CHKD". Otherwise this is zero. */ +/* 16*/ le32 system_page_size; /* Byte size of system pages when the log file + was created, has to be >= 512 and a power of + 2. Use this to calculate the required size + of the usa (usa_count) and add it to usa_ofs. + Then verify that the result is less than the + value of the restart_area_offset. */ +/* 20*/ le32 log_page_size; /* Byte size of log file pages, has to be >= + 512 and a power of 2. The default is 4096 + and is used when the system page size is + between 4096 and 8192. Otherwise this is + set to the system page size instead. */ +/* 24*/ le16 restart_area_offset;/* Byte offset from the start of this header to + the RESTART_AREA. Value has to be aligned + to 8-byte boundary. When creating, set this + to be after the usa. */ +/* 26*/ sle16 minor_ver; /* Log file minor version. Only check if major + version is 1. */ +/* 28*/ sle16 major_ver; /* Log file major version. We only support + version 1.1. */ +/* sizeof() = 30 (0x1e) bytes */ +} __attribute__((__packed__)) RESTART_PAGE_HEADER; + +/* + * Constant for the log client indices meaning that there are no client records + * in this particular client array. Also inside the client records themselves, + * this means that there are no client records preceding or following this one. + */ +#define LOGFILE_NO_CLIENT const_cpu_to_le16(0xffff) +#define LOGFILE_NO_CLIENT_CPU 0xffff + +/* + * These are the so far known RESTART_AREA_* flags (16-bit) which contain + * information about the log file in which they are present. + */ +enum { + RESTART_VOLUME_IS_CLEAN = const_cpu_to_le16(0x0002), + RESTART_SPACE_FILLER = 0xffff, /* gcc: Force enum bit width to 16. */ +} __attribute__((__packed__)); + +typedef le16 RESTART_AREA_FLAGS; + +/** + * struct RESTART_AREA - Log file restart area record. + * + * The offset of this record is found by adding the offset of the + * RESTART_PAGE_HEADER to the restart_area_offset value found in it. + * See notes at restart_area_offset above. + */ +typedef struct { +/*Ofs*/ +/* 0*/ leLSN current_lsn; /* The current, i.e. last LSN inside the log + when the restart area was last written. + This happens often but what is the interval? + Is it just fixed time or is it every time a + check point is written or something else? + On create set to 0. */ +/* 8*/ le16 log_clients; /* Number of log client records in the array of + log client records which follows this + restart area. Must be 1. */ +/* 10*/ le16 client_free_list; /* The index of the first free log client record + in the array of log client records. + LOGFILE_NO_CLIENT means that there are no + free log client records in the array. + If != LOGFILE_NO_CLIENT, check that + log_clients > client_free_list. On Win2k + and presumably earlier, on a clean volume + this is != LOGFILE_NO_CLIENT, and it should + be 0, i.e. the first (and only) client + record is free and thus the logfile is + closed and hence clean. A dirty volume + would have left the logfile open and hence + this would be LOGFILE_NO_CLIENT. On WinXP + and presumably later, the logfile is always + open, even on clean shutdown so this should + always be LOGFILE_NO_CLIENT. */ +/* 12*/ le16 client_in_use_list;/* The index of the first in-use log client + record in the array of log client records. + LOGFILE_NO_CLIENT means that there are no + in-use log client records in the array. If + != LOGFILE_NO_CLIENT check that log_clients + > client_in_use_list. On Win2k and + presumably earlier, on a clean volume this + is LOGFILE_NO_CLIENT, i.e. there are no + client records in use and thus the logfile + is closed and hence clean. A dirty volume + would have left the logfile open and hence + this would be != LOGFILE_NO_CLIENT, and it + should be 0, i.e. the first (and only) + client record is in use. On WinXP and + presumably later, the logfile is always + open, even on clean shutdown so this should + always be 0. */ +/* 14*/ RESTART_AREA_FLAGS flags;/* Flags modifying LFS behaviour. On Win2k + and presumably earlier this is always 0. On + WinXP and presumably later, if the logfile + was shutdown cleanly, the second bit, + RESTART_VOLUME_IS_CLEAN, is set. This bit + is cleared when the volume is mounted by + WinXP and set when the volume is dismounted, + thus if the logfile is dirty, this bit is + clear. Thus we don't need to check the + Windows version to determine if the logfile + is clean. Instead if the logfile is closed, + we know it must be clean. If it is open and + this bit is set, we also know it must be + clean. If on the other hand the logfile is + open and this bit is clear, we can be almost + certain that the logfile is dirty. */ +/* 16*/ le32 seq_number_bits; /* How many bits to use for the sequence + number. This is calculated as 67 - the + number of bits required to store the logfile + size in bytes and this can be used in with + the specified file_size as a consistency + check. */ +/* 20*/ le16 restart_area_length;/* Length of the restart area including the + client array. Following checks required if + version matches. Otherwise, skip them. + restart_area_offset + restart_area_length + has to be <= system_page_size. Also, + restart_area_length has to be >= + client_array_offset + (log_clients * + sizeof(log client record)). */ +/* 22*/ le16 client_array_offset;/* Offset from the start of this record to + the first log client record if versions are + matched. When creating, set this to be + after this restart area structure, aligned + to 8-bytes boundary. If the versions do not + match, this is ignored and the offset is + assumed to be (sizeof(RESTART_AREA) + 7) & + ~7, i.e. rounded up to first 8-byte + boundary. Either way, client_array_offset + has to be aligned to an 8-byte boundary. + Also, restart_area_offset + + client_array_offset has to be <= 510. + Finally, client_array_offset + (log_clients + * sizeof(log client record)) has to be <= + system_page_size. On Win2k and presumably + earlier, this is 0x30, i.e. immediately + following this record. On WinXP and + presumably later, this is 0x40, i.e. there + are 16 extra bytes between this record and + the client array. This probably means that + the RESTART_AREA record is actually bigger + in WinXP and later. */ +/* 24*/ sle64 file_size; /* Usable byte size of the log file. If the + restart_area_offset + the offset of the + file_size are > 510 then corruption has + occurred. This is the very first check when + starting with the restart_area as if it + fails it means that some of the above values + will be corrupted by the multi sector + transfer protection. The file_size has to + be rounded down to be a multiple of the + log_page_size in the RESTART_PAGE_HEADER and + then it has to be at least big enough to + store the two restart pages and 48 (0x30) + log record pages. */ +/* 32*/ le32 last_lsn_data_length;/* Length of data of last LSN, not including + the log record header. On create set to + 0. */ +/* 36*/ le16 log_record_header_length;/* Byte size of the log record header. + If the version matches then check that the + value of log_record_header_length is a + multiple of 8, i.e. + (log_record_header_length + 7) & ~7 == + log_record_header_length. When creating set + it to sizeof(LOG_RECORD_HEADER), aligned to + 8 bytes. */ +/* 38*/ le16 log_page_data_offset;/* Offset to the start of data in a log record + page. Must be a multiple of 8. On create + set it to immediately after the update + sequence array of the log record page. */ +/* 40*/ le32 restart_log_open_count;/* A counter that gets incremented every + time the logfile is restarted which happens + at mount time when the logfile is opened. + When creating set to a random value. Win2k + sets it to the low 32 bits of the current + system time in NTFS format (see time.h). */ +/* 44*/ le32 reserved; /* Reserved/alignment to 8-byte boundary. */ +/* sizeof() = 48 (0x30) bytes */ +} __attribute__((__packed__)) RESTART_AREA; + +/** + * struct LOG_CLIENT_RECORD - Log client record. + * + * The offset of this record is found by adding the offset of the + * RESTART_AREA to the client_array_offset value found in it. + */ +typedef struct { +/*Ofs*/ +/* 0*/ leLSN oldest_lsn; /* Oldest LSN needed by this client. On create + set to 0. */ +/* 8*/ leLSN client_restart_lsn;/* LSN at which this client needs to restart + the volume, i.e. the current position within + the log file. At present, if clean this + should = current_lsn in restart area but it + probably also = current_lsn when dirty most + of the time. At create set to 0. */ +/* 16*/ le16 prev_client; /* The offset to the previous log client record + in the array of log client records. + LOGFILE_NO_CLIENT means there is no previous + client record, i.e. this is the first one. + This is always LOGFILE_NO_CLIENT. */ +/* 18*/ le16 next_client; /* The offset to the next log client record in + the array of log client records. + LOGFILE_NO_CLIENT means there are no next + client records, i.e. this is the last one. + This is always LOGFILE_NO_CLIENT. */ +/* 20*/ le16 seq_number; /* On Win2k and presumably earlier, this is set + to zero every time the logfile is restarted + and it is incremented when the logfile is + closed at dismount time. Thus it is 0 when + dirty and 1 when clean. On WinXP and + presumably later, this is always 0. */ +/* 22*/ u8 reserved[6]; /* Reserved/alignment. */ +/* 28*/ le32 client_name_length;/* Length of client name in bytes. Should + always be 8. */ +/* 32*/ ntfschar client_name[64];/* Name of the client in Unicode. Should + always be "NTFS" with the remaining bytes + set to 0. */ +/* sizeof() = 160 (0xa0) bytes */ +} __attribute__((__packed__)) LOG_CLIENT_RECORD; + +/** + * struct RECORD_PAGE_HEADER - Log page record page header. + * + * Each log page begins with this header and is followed by several LOG_RECORD + * structures, starting at offset 0x40 (the size of this structure and the + * following update sequence array and then aligned to 8 byte boundary, but is + * this specified anywhere?). + */ +typedef struct { +/* 0 NTFS_RECORD; -- Unfolded here as gcc doesn't like unnamed structs. */ + NTFS_RECORD_TYPES magic;/* Usually the magic is "RCRD". */ + u16 usa_ofs; /* See NTFS_RECORD definition in layout.h. + When creating, set this to be immediately + after this header structure (without any + alignment). */ + u16 usa_count; /* See NTFS_RECORD definition in layout.h. */ + + union { + LSN last_lsn; + s64 file_offset; + } __attribute__((__packed__)) copy; + u32 flags; + u16 page_count; + u16 page_position; + union { + struct { + u16 next_record_offset; + u8 reserved[6]; + LSN last_end_lsn; + } __attribute__((__packed__)) packed; + } __attribute__((__packed__)) header; +} __attribute__((__packed__)) RECORD_PAGE_HEADER; + +/** + * enum LOG_RECORD_FLAGS - Possible 16-bit flags for log records. + * + * (Or is it log record pages?) + */ +typedef enum { + LOG_RECORD_MULTI_PAGE = const_cpu_to_le16(0x0001), /* ??? */ + LOG_RECORD_SIZE_PLACE_HOLDER = 0xffff, + /* This has nothing to do with the log record. It is only so + gcc knows to make the flags 16-bit. */ +} __attribute__((__packed__)) LOG_RECORD_FLAGS; + +/** + * struct LOG_CLIENT_ID - The log client id structure identifying a log client. + */ +typedef struct { + u16 seq_number; + u16 client_index; +} __attribute__((__packed__)) LOG_CLIENT_ID; + +/** + * struct LOG_RECORD - Log record header. + * + * Each log record seems to have a constant size of 0x70 bytes. + */ +typedef struct { + LSN this_lsn; + LSN client_previous_lsn; + LSN client_undo_next_lsn; + u32 client_data_length; + LOG_CLIENT_ID client_id; + u32 record_type; + u32 transaction_id; + u16 flags; + u16 reserved_or_alignment[3]; +/* Now are at ofs 0x30 into struct. */ + u16 redo_operation; + u16 undo_operation; + u16 redo_offset; + u16 redo_length; + u16 undo_offset; + u16 undo_length; + u16 target_attribute; + u16 lcns_to_follow; /* Number of lcn_list entries + following this entry. */ +/* Now at ofs 0x40. */ + u16 record_offset; + u16 attribute_offset; + u32 alignment_or_reserved; + VCN target_vcn; +/* Now at ofs 0x50. */ + struct { /* Only present if lcns_to_follow + is not 0. */ + LCN lcn; + } __attribute__((__packed__)) lcn_list[0]; +} __attribute__((__packed__)) LOG_RECORD; + +extern BOOL ntfs_check_logfile(ntfs_attr *log_na, RESTART_PAGE_HEADER **rp); +extern BOOL ntfs_is_logfile_clean(ntfs_attr *log_na, RESTART_PAGE_HEADER *rp); +extern int ntfs_empty_logfile(ntfs_attr *na); + +#endif /* defined _NTFS_LOGFILE_H */ diff --git a/include/ntfs-3g/logging.h b/include/ntfs-3g/logging.h new file mode 100755 index 0000000..401f5c9 --- a/dev/null +++ b/include/ntfs-3g/logging.h @@ -0,0 +1,118 @@ +/* + * logging.h - Centralised logging. Originated from the Linux-NTFS project. + * + * Copyright (c) 2005 Richard Russon + * Copyright (c) 2007-2008 Szabolcs Szakacsits + * + * This program/include file 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/include file 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 (in the main directory of the NTFS-3G + * distribution in the file COPYING); if not, write to the Free Software + * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _LOGGING_H_ +#define _LOGGING_H_ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_STDARG_H +#include +#endif + +#include "types.h" + +/* Function prototype for the logging handlers */ +typedef int (ntfs_log_handler)(const char *function, const char *file, int line, + u32 level, void *data, const char *format, va_list args); + +/* Set the logging handler from one of the functions, below. */ +void ntfs_log_set_handler(ntfs_log_handler *handler + __attribute__((format(printf, 6, 0)))); + +/* Logging handlers */ +ntfs_log_handler ntfs_log_handler_syslog __attribute__((format(printf, 6, 0))); +ntfs_log_handler ntfs_log_handler_fprintf __attribute__((format(printf, 6, 0))); +ntfs_log_handler ntfs_log_handler_null __attribute__((format(printf, 6, 0))); +ntfs_log_handler ntfs_log_handler_stdout __attribute__((format(printf, 6, 0))); +ntfs_log_handler ntfs_log_handler_outerr __attribute__((format(printf, 6, 0))); +ntfs_log_handler ntfs_log_handler_stderr __attribute__((format(printf, 6, 0))); + +/* Enable/disable certain log levels */ +u32 ntfs_log_set_levels(u32 levels); +u32 ntfs_log_clear_levels(u32 levels); +u32 ntfs_log_get_levels(void); + +/* Enable/disable certain log flags */ +u32 ntfs_log_set_flags(u32 flags); +u32 ntfs_log_clear_flags(u32 flags); +u32 ntfs_log_get_flags(void); + +/* Turn command-line options into logging flags */ +BOOL ntfs_log_parse_option(const char *option); + +int ntfs_log_redirect(const char *function, const char *file, int line, + u32 level, void *data, const char *format, ...) + __attribute__((format(printf, 6, 7))); + +/* Logging levels - Determine what gets logged */ +#define NTFS_LOG_LEVEL_DEBUG (1 << 0) /* x = 42 */ +#define NTFS_LOG_LEVEL_TRACE (1 << 1) /* Entering function x() */ +#define NTFS_LOG_LEVEL_QUIET (1 << 2) /* Quietable output */ +#define NTFS_LOG_LEVEL_INFO (1 << 3) /* Volume needs defragmenting */ +#define NTFS_LOG_LEVEL_VERBOSE (1 << 4) /* Forced to continue */ +#define NTFS_LOG_LEVEL_PROGRESS (1 << 5) /* 54% complete */ +#define NTFS_LOG_LEVEL_WARNING (1 << 6) /* You should backup before starting */ +#define NTFS_LOG_LEVEL_ERROR (1 << 7) /* Operation failed, no damage done */ +#define NTFS_LOG_LEVEL_PERROR (1 << 8) /* Message : standard error description */ +#define NTFS_LOG_LEVEL_CRITICAL (1 << 9) /* Operation failed,damage may have occurred */ +#define NTFS_LOG_LEVEL_ENTER (1 << 10) /* Enter a function */ +#define NTFS_LOG_LEVEL_LEAVE (1 << 11) /* Leave a function */ + +/* Logging style flags - Manage the style of the output */ +#define NTFS_LOG_FLAG_PREFIX (1 << 0) /* Prefix messages with "ERROR: ", etc */ +#define NTFS_LOG_FLAG_FILENAME (1 << 1) /* Show the file origin of the message */ +#define NTFS_LOG_FLAG_LINE (1 << 2) /* Show the line number of the message */ +#define NTFS_LOG_FLAG_FUNCTION (1 << 3) /* Show the function name containing the message */ +#define NTFS_LOG_FLAG_ONLYNAME (1 << 4) /* Only display the filename, not the pathname */ + +/* Macros to simplify logging. One for each level defined above. + * Note, ntfs_log_debug/trace have effect only if DEBUG is defined. + */ +#define ntfs_log_critical(FORMAT, ARGS...) ntfs_log_redirect(__FUNCTION__,__FILE__,__LINE__,NTFS_LOG_LEVEL_CRITICAL,NULL,FORMAT,##ARGS) +#define ntfs_log_error(FORMAT, ARGS...) ntfs_log_redirect(__FUNCTION__,__FILE__,__LINE__,NTFS_LOG_LEVEL_ERROR,NULL,FORMAT,##ARGS) +#define ntfs_log_info(FORMAT, ARGS...) ntfs_log_redirect(__FUNCTION__,__FILE__,__LINE__,NTFS_LOG_LEVEL_INFO,NULL,FORMAT,##ARGS) +#define ntfs_log_perror(FORMAT, ARGS...) ntfs_log_redirect(__FUNCTION__,__FILE__,__LINE__,NTFS_LOG_LEVEL_PERROR,NULL,FORMAT,##ARGS) +#define ntfs_log_progress(FORMAT, ARGS...) ntfs_log_redirect(__FUNCTION__,__FILE__,__LINE__,NTFS_LOG_LEVEL_PROGRESS,NULL,FORMAT,##ARGS) +#define ntfs_log_quiet(FORMAT, ARGS...) ntfs_log_redirect(__FUNCTION__,__FILE__,__LINE__,NTFS_LOG_LEVEL_QUIET,NULL,FORMAT,##ARGS) +#define ntfs_log_verbose(FORMAT, ARGS...) ntfs_log_redirect(__FUNCTION__,__FILE__,__LINE__,NTFS_LOG_LEVEL_VERBOSE,NULL,FORMAT,##ARGS) +#define ntfs_log_warning(FORMAT, ARGS...) ntfs_log_redirect(__FUNCTION__,__FILE__,__LINE__,NTFS_LOG_LEVEL_WARNING,NULL,FORMAT,##ARGS) + +/* By default debug and trace messages are compiled into the program, + * but not displayed. + */ +#ifdef DEBUG +#define ntfs_log_debug(FORMAT, ARGS...) ntfs_log_redirect(__FUNCTION__,__FILE__,__LINE__,NTFS_LOG_LEVEL_DEBUG,NULL,FORMAT,##ARGS) +#define ntfs_log_trace(FORMAT, ARGS...) ntfs_log_redirect(__FUNCTION__,__FILE__,__LINE__,NTFS_LOG_LEVEL_TRACE,NULL,FORMAT,##ARGS) +#define ntfs_log_enter(FORMAT, ARGS...) ntfs_log_redirect(__FUNCTION__,__FILE__,__LINE__,NTFS_LOG_LEVEL_ENTER,NULL,FORMAT,##ARGS) +#define ntfs_log_leave(FORMAT, ARGS...) ntfs_log_redirect(__FUNCTION__,__FILE__,__LINE__,NTFS_LOG_LEVEL_LEAVE,NULL,FORMAT,##ARGS) +#else +#define ntfs_log_debug(FORMAT, ARGS...)do {} while (0) +#define ntfs_log_trace(FORMAT, ARGS...)do {} while (0) +#define ntfs_log_enter(FORMAT, ARGS...)do {} while (0) +#define ntfs_log_leave(FORMAT, ARGS...)do {} while (0) +#endif /* DEBUG */ + +#endif /* _LOGGING_H_ */ + diff --git a/include/ntfs-3g/mft.h b/include/ntfs-3g/mft.h new file mode 100755 index 0000000..bb15f0f --- a/dev/null +++ b/include/ntfs-3g/mft.h @@ -0,0 +1,132 @@ +/* + * mft.h - Exports for MFT record handling. Originated from the Linux-NTFS project. + * + * Copyright (c) 2000-2002 Anton Altaparmakov + * Copyright (c) 2004-2005 Richard Russon + * Copyright (c) 2006-2008 Szabolcs Szakacsits + * + * This program/include file 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/include file 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 (in the main directory of the NTFS-3G + * distribution in the file COPYING); if not, write to the Free Software + * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _NTFS_MFT_H +#define _NTFS_MFT_H + +#include "volume.h" +#include "inode.h" +#include "layout.h" +#include "logging.h" + +extern int ntfs_mft_records_read(const ntfs_volume *vol, const MFT_REF mref, + const s64 count, MFT_RECORD *b); + +/** + * ntfs_mft_record_read - read a record from the mft + * @vol: volume to read from + * @mref: mft record number to read + * @b: output data buffer + * + * Read the mft record specified by @mref from volume @vol into buffer @b. + * Return 0 on success or -1 on error, with errno set to the error code. + * + * The read mft record is mst deprotected and is hence ready to use. The caller + * should check the record with is_baad_record() in case mst deprotection + * failed. + * + * NOTE: @b has to be at least of size vol->mft_record_size. + */ +static __inline__ int ntfs_mft_record_read(const ntfs_volume *vol, + const MFT_REF mref, MFT_RECORD *b) +{ + int ret; + + ntfs_log_enter("Entering for inode %lld\n", (long long)MREF(mref)); + ret = ntfs_mft_records_read(vol, mref, 1, b); + ntfs_log_leave("\n"); + return ret; +} + +extern int ntfs_mft_record_check(const ntfs_volume *vol, const MFT_REF mref, + MFT_RECORD *m); + +extern int ntfs_file_record_read(const ntfs_volume *vol, const MFT_REF mref, + MFT_RECORD **mrec, ATTR_RECORD **attr); + +extern int ntfs_mft_records_write(const ntfs_volume *vol, const MFT_REF mref, + const s64 count, MFT_RECORD *b); + +/** + * ntfs_mft_record_write - write an mft record to disk + * @vol: volume to write to + * @mref: mft record number to write + * @b: data buffer containing the mft record to write + * + * Write the mft record specified by @mref from buffer @b to volume @vol. + * Return 0 on success or -1 on error, with errno set to the error code. + * + * Before the mft record is written, it is mst protected. After the write, it + * is deprotected again, thus resulting in an increase in the update sequence + * number inside the buffer @b. + * + * NOTE: @b has to be at least of size vol->mft_record_size. + */ +static __inline__ int ntfs_mft_record_write(const ntfs_volume *vol, + const MFT_REF mref, MFT_RECORD *b) +{ + int ret; + + ntfs_log_enter("Entering for inode %lld\n", (long long)MREF(mref)); + ret = ntfs_mft_records_write(vol, mref, 1, b); + ntfs_log_leave("\n"); + return ret; +} + +/** + * ntfs_mft_record_get_data_size - return number of bytes used in mft record @b + * @m: mft record to get the data size of + * + * Takes the mft record @m and returns the number of bytes used in the record + * or 0 on error (i.e. @m is not a valid mft record). Zero is not a valid size + * for an mft record as it at least has to have the MFT_RECORD itself and a + * zero length attribute of type AT_END, thus making the minimum size 56 bytes. + * + * Aside: The size is independent of NTFS versions 1.x/3.x because the 8-byte + * alignment of the first attribute mask the difference in MFT_RECORD size + * between NTFS 1.x and 3.x. Also, you would expect every mft record to + * contain an update sequence array as well but that could in theory be + * non-existent (don't know if Windows' NTFS driver/chkdsk wouldn't view this + * as corruption in itself though). + */ +static __inline__ u32 ntfs_mft_record_get_data_size(const MFT_RECORD *m) +{ + if (!m || !ntfs_is_mft_record(m->magic)) + return 0; + /* Get the number of used bytes and return it. */ + return le32_to_cpu(m->bytes_in_use); +} + +extern int ntfs_mft_record_layout(const ntfs_volume *vol, const MFT_REF mref, + MFT_RECORD *mrec); + +extern int ntfs_mft_record_format(const ntfs_volume *vol, const MFT_REF mref); + +extern ntfs_inode *ntfs_mft_record_alloc(ntfs_volume *vol, ntfs_inode *base_ni); + +extern int ntfs_mft_record_free(ntfs_volume *vol, ntfs_inode *ni); + +extern int ntfs_mft_usn_dec(MFT_RECORD *mrec); + +#endif /* defined _NTFS_MFT_H */ + diff --git a/include/ntfs-3g/misc.h b/include/ntfs-3g/misc.h new file mode 100755 index 0000000..a03e964 --- a/dev/null +++ b/include/ntfs-3g/misc.h @@ -0,0 +1,30 @@ +/* + * misc.h : miscellaneous exports + * - memory allocation + * + * Copyright (c) 2008 Jean-Pierre Andre + * + * This program/include file 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/include file 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 (in the main directory of the NTFS-3G + * distribution in the file COPYING); if not, write to the Free Software + * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _NTFS_MISC_H_ +#define _NTFS_MISC_H_ + +void *ntfs_calloc(size_t size); +void *ntfs_malloc(size_t size); + +#endif /* _NTFS_MISC_H_ */ + diff --git a/include/ntfs-3g/mst.h b/include/ntfs-3g/mst.h new file mode 100755 index 0000000..ca81382 --- a/dev/null +++ b/include/ntfs-3g/mst.h @@ -0,0 +1,34 @@ +/* + * mst.h - Exports for multi sector transfer fixup functions. + * Originated from the Linux-NTFS project. + * + * Copyright (c) 2000-2002 Anton Altaparmakov + * + * This program/include file 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/include file 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 (in the main directory of the NTFS-3G + * distribution in the file COPYING); if not, write to the Free Software + * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _NTFS_MST_H +#define _NTFS_MST_H + +#include "types.h" +#include "layout.h" + +extern int ntfs_mst_post_read_fixup(NTFS_RECORD *b, const u32 size); +extern int ntfs_mst_pre_write_fixup(NTFS_RECORD *b, const u32 size); +extern void ntfs_mst_post_write_fixup(NTFS_RECORD *b); + +#endif /* defined _NTFS_MST_H */ + diff --git a/include/ntfs-3g/ntfstime.h b/include/ntfs-3g/ntfstime.h new file mode 100755 index 0000000..2225d39 --- a/dev/null +++ b/include/ntfs-3g/ntfstime.h @@ -0,0 +1,131 @@ +/* + * ntfstime.h - NTFS time related functions. Originated from the Linux-NTFS project. + * + * Copyright (c) 2005 Anton Altaparmakov + * Copyright (c) 2005 Yura Pakhuchiy + * Copyright (c) 2010 Jean-Pierre Andre + * + * This program/include file 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/include file 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 (in the main directory of the NTFS-3G + * distribution in the file COPYING); if not, write to the Free Software + * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _NTFS_NTFSTIME_H +#define _NTFS_NTFSTIME_H + +#ifdef HAVE_TIME_H +#include +#endif +#ifdef HAVE_SYS_STAT_H +#include +#endif +#ifdef HAVE_GETTIMEOFDAY +#include +#endif + +#include "types.h" + +/* + * assume "struct timespec" is not defined if st_mtime is not defined + */ +#if !defined(st_mtime) & !defined(__timespec_defined) +/*struct timespec { + time_t tv_sec; + long tv_nsec; +} */; +#endif + +/* + * There are four times more conversions of internal representation + * to ntfs representation than any other conversion, so the most + * efficient internal representation is ntfs representation + * (with low endianness) + */ +typedef sle64 ntfs_time; + +#define NTFS_TIME_OFFSET ((s64)(369 * 365 + 89) * 24 * 3600 * 10000000) + +/** + * ntfs2timespec - Convert an NTFS time to Unix time + * @ntfs_time: An NTFS time in 100ns units since 1601 + * + * NTFS stores times as the number of 100ns intervals since January 1st 1601 at + * 00:00 UTC. This system will not suffer from Y2K problems until ~57000AD. + * + * Return: A Unix time (number of seconds since 1970, and nanoseconds) + */ +static __inline__ struct timespec ntfs2timespec(ntfs_time ntfstime) +{ + struct timespec spec; + s64 cputime; + + cputime = sle64_to_cpu(ntfstime); + spec.tv_sec = (cputime - (NTFS_TIME_OFFSET)) / 10000000; + spec.tv_nsec = (cputime - (NTFS_TIME_OFFSET) + - (s64)spec.tv_sec*10000000)*100; + /* force zero nsec for overflowing dates */ + if ((spec.tv_nsec < 0) || (spec.tv_nsec > 999999999)) + spec.tv_nsec = 0; + return (spec); +} + +/** + * timespec2ntfs - Convert Linux time to NTFS time + * @utc_time: Linux time to convert to NTFS + * + * Convert the Linux time @utc_time to its corresponding NTFS time. + * + * Linux stores time in a long at present and measures it as the number of + * 1-second intervals since 1st January 1970, 00:00:00 UTC + * with a separated non-negative nanosecond value + * + * NTFS uses Microsoft's standard time format which is stored in a sle64 and is + * measured as the number of 100 nano-second intervals since 1st January 1601, + * 00:00:00 UTC. + * + * Return: An NTFS time (100ns units since Jan 1601) + */ +static __inline__ ntfs_time timespec2ntfs(struct timespec spec) +{ + s64 units; + + units = (s64)spec.tv_sec * 10000000 + + NTFS_TIME_OFFSET + spec.tv_nsec/100; + return (cpu_to_le64(units)); +} + +/* + * Return the current time in ntfs format + */ + +static __inline__ ntfs_time ntfs_current_time(void) +{ + struct timespec now; + +#if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_SYS_CLOCK_GETTIME) + clock_gettime(CLOCK_REALTIME, &now); +#elif defined(HAVE_GETTIMEOFDAY) + struct timeval microseconds; + + gettimeofday(µseconds, (struct timezone*)NULL); + now.tv_sec = microseconds.tv_sec; + now.tv_nsec = microseconds.tv_usec*1000; +#else + now.tv_sec = time((time_t*)NULL); + now.tv_nsec = 0; +#endif + return (timespec2ntfs(now)); +} + +#endif /* _NTFS_NTFSTIME_H */ diff --git a/include/ntfs-3g/object_id.h b/include/ntfs-3g/object_id.h new file mode 100755 index 0000000..31af9fd --- a/dev/null +++ b/include/ntfs-3g/object_id.h @@ -0,0 +1,35 @@ +/* + * + * Copyright (c) 2008 Jean-Pierre Andre + * + */ + +/* + * 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 (in the main directory of the NTFS-3G + * distribution in the file COPYING); if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef OBJECT_ID_H +#define OBJECT_ID_H + +int ntfs_get_ntfs_object_id(ntfs_inode *ni, char *value, size_t size); + +int ntfs_set_ntfs_object_id(ntfs_inode *ni, const char *value, + size_t size, int flags); +int ntfs_remove_ntfs_object_id(ntfs_inode *ni); + +int ntfs_delete_object_id_index(ntfs_inode *ni); + +#endif /* OBJECT_ID_H */ diff --git a/include/ntfs-3g/param.h b/include/ntfs-3g/param.h new file mode 100755 index 0000000..b309e30 --- a/dev/null +++ b/include/ntfs-3g/param.h @@ -0,0 +1,63 @@ +/* + * param.h - Parameter values for ntfs-3g + * + * Copyright (c) 2009 Jean-Pierre Andre + * + * This program/include file 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/include file 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 (in the main directory of the NTFS-3G + * distribution in the file COPYING); if not, write to the Free Software + * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _NTFS_PARAM_H +#define _NTFS_PARAM_H + +#define CACHE_INODE_SIZE 32 /* inode cache, zero or >= 3 and not too big */ +#define CACHE_NIDATA_SIZE 64 /* idata cache, zero or >= 3 and not too big */ +#define CACHE_LOOKUP_SIZE 64 /* lookup cache, zero or >= 3 and not too big */ +#define CACHE_SECURID_SIZE 16 /* securid cache, zero or >= 3 and not too big */ +#define CACHE_LEGACY_SIZE 8 /* legacy cache size, zero or >= 3 and not too big */ + +#define FORCE_FORMAT_v1x 0 /* Insert security data as in NTFS v1.x */ +#define OWNERFROMACL 1 /* Get the owner from ACL (not Windows owner) */ + +/* + * Permission checking modes for high level and low level + * + * The choices for high and low lowel are independent, they have + * no effect on the library + * + * Stick to the recommended values unless you understand the consequences + * on protection and performances. Use of cacheing is good for + * performances, but bad on security. + * + * Possible values for high level : + * 1 : no cache, kernel control (recommended) + * 4 : no cache, file system control + * 7 : no cache, kernel control for ACLs + * + * Possible values for low level : + * 2 : no cache, kernel control + * 3 : use kernel/fuse cache, kernel control + * 5 : no cache, file system control (recommended) + * 8 : no cache, kernel control for ACLs + * + * Use of options 7 and 8 requires a patch to fuse + * When Posix ACLs are selected in the configure options, a value + * of 6 is added in the mount report. + */ + +#define HPERMSCONFIG 1 +#define LPERMSCONFIG 5 + +#endif /* defined _NTFS_PARAM_H */ diff --git a/include/ntfs-3g/reparse.h b/include/ntfs-3g/reparse.h new file mode 100755 index 0000000..35f4aa4 --- a/dev/null +++ b/include/ntfs-3g/reparse.h @@ -0,0 +1,39 @@ +/* + * + * Copyright (c) 2008 Jean-Pierre Andre + * + */ + +/* + * 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 (in the main directory of the NTFS-3G + * distribution in the file COPYING); if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef REPARSE_H +#define REPARSE_H + +char *ntfs_make_symlink(ntfs_inode *ni, const char *mnt_point, + int *pattr_size); +BOOL ntfs_possible_symlink(ntfs_inode *ni); + +int ntfs_get_ntfs_reparse_data(ntfs_inode *ni, char *value, size_t size); + +int ntfs_set_ntfs_reparse_data(ntfs_inode *ni, const char *value, + size_t size, int flags); +int ntfs_remove_ntfs_reparse_data(ntfs_inode *ni); + +int ntfs_delete_reparse_index(ntfs_inode *ni); + +#endif /* REPARSE_H */ diff --git a/include/ntfs-3g/runlist.h b/include/ntfs-3g/runlist.h new file mode 100755 index 0000000..43de53c --- a/dev/null +++ b/include/ntfs-3g/runlist.h @@ -0,0 +1,89 @@ +/* + * runlist.h - Exports for runlist handling. Originated from the Linux-NTFS project. + * + * Copyright (c) 2002 Anton Altaparmakov + * Copyright (c) 2002 Richard Russon + * + * This program/include file 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/include file 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 (in the main directory of the NTFS-3G + * distribution in the file COPYING); if not, write to the Free Software + * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _NTFS_RUNLIST_H +#define _NTFS_RUNLIST_H + +#include "types.h" + +/* Forward declarations */ +typedef struct _runlist_element runlist_element; +typedef runlist_element runlist; + +#include "attrib.h" +#include "volume.h" + +/** + * struct _runlist_element - in memory vcn to lcn mapping array element. + * @vcn: starting vcn of the current array element + * @lcn: starting lcn of the current array element + * @length: length in clusters of the current array element + * + * The last vcn (in fact the last vcn + 1) is reached when length == 0. + * + * When lcn == -1 this means that the count vcns starting at vcn are not + * physically allocated (i.e. this is a hole / data is sparse). + */ +struct _runlist_element {/* In memory vcn to lcn mapping structure element. */ + VCN vcn; /* vcn = Starting virtual cluster number. */ + LCN lcn; /* lcn = Starting logical cluster number. */ + s64 length; /* Run length in clusters. */ +}; + +extern runlist_element *ntfs_rl_extend(runlist_element *rl, int more_entries); + +extern LCN ntfs_rl_vcn_to_lcn(const runlist_element *rl, const VCN vcn); + +extern s64 ntfs_rl_pread(const ntfs_volume *vol, const runlist_element *rl, + const s64 pos, s64 count, void *b); +extern s64 ntfs_rl_pwrite(const ntfs_volume *vol, const runlist_element *rl, + s64 ofs, const s64 pos, s64 count, void *b); + +extern runlist_element *ntfs_runlists_merge(runlist_element *drl, + runlist_element *srl); + +extern runlist_element *ntfs_mapping_pairs_decompress(const ntfs_volume *vol, + const ATTR_RECORD *attr, runlist_element *old_rl); + +extern int ntfs_get_nr_significant_bytes(const s64 n); + +extern int ntfs_get_size_for_mapping_pairs(const ntfs_volume *vol, + const runlist_element *rl, const VCN start_vcn, int max_size); + +extern int ntfs_write_significant_bytes(u8 *dst, const u8 *dst_max, + const s64 n); + +extern int ntfs_mapping_pairs_build(const ntfs_volume *vol, u8 *dst, + const int dst_len, const runlist_element *rl, + const VCN start_vcn, runlist_element const **stop_rl); + +extern int ntfs_rl_truncate(runlist **arl, const VCN start_vcn); + +extern int ntfs_rl_sparse(runlist *rl); +extern s64 ntfs_rl_get_compressed_size(ntfs_volume *vol, runlist *rl); + +#ifdef NTFS_TEST +int test_rl_main(int argc, char *argv[]); +#endif + +#endif /* defined _NTFS_RUNLIST_H */ + diff --git a/include/ntfs-3g/security.h b/include/ntfs-3g/security.h new file mode 100755 index 0000000..f95c331 --- a/dev/null +++ b/include/ntfs-3g/security.h @@ -0,0 +1,353 @@ +/* + * security.h - Exports for handling security/ACLs in NTFS. + * Originated from the Linux-NTFS project. + * + * Copyright (c) 2004 Anton Altaparmakov + * Copyright (c) 2005-2006 Szabolcs Szakacsits + * Copyright (c) 2007-2008 Jean-Pierre Andre + * + * This program/include file 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/include file 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 (in the main directory of the NTFS-3G + * distribution in the file COPYING); if not, write to the Free Software + * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _NTFS_SECURITY_H +#define _NTFS_SECURITY_H + +#include "types.h" +#include "layout.h" +#include "inode.h" +#include "dir.h" + +#ifndef POSIXACLS +#define POSIXACLS 0 +#endif + +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define const_cpu_to_be16(x) ((((x) & 255L) << 8) + (((x) >> 8) & 255L)) +#define const_cpu_to_be32(x) ((((x) & 255L) << 24) + (((x) & 0xff00L) << 8) \ + + (((x) >> 8) & 0xff00L) + (((x) >> 24) & 255L)) +#else +#define const_cpu_to_be16(x) (x) +#define const_cpu_to_be32(x) (x) +#endif + +/* + * item in the mapping list + */ + +struct MAPPING { + struct MAPPING *next; + int xid; /* linux id : uid or gid */ + SID *sid; /* Windows id : usid or gsid */ + int grcnt; /* group count (for users only) */ + gid_t *groups; /* groups which the user is member of */ +}; + +/* + * Entry in the permissions cache + * Note : this cache is not organized as a generic cache + */ + +struct CACHED_PERMISSIONS { + uid_t uid; + gid_t gid; + le32 inh_fileid; + le32 inh_dirid; +#if POSIXACLS + struct POSIX_SECURITY *pxdesc; + unsigned int pxdescsize:16; +#endif + unsigned int mode:12; + unsigned int valid:1; +} ; + +/* + * Entry in the permissions cache for directories with no security_id + */ + +struct CACHED_PERMISSIONS_LEGACY { + struct CACHED_PERMISSIONS_LEGACY *next; + struct CACHED_PERMISSIONS_LEGACY *previous; + void *variable; + size_t varsize; + /* above fields must match "struct CACHED_GENERIC" */ + u64 mft_no; + struct CACHED_PERMISSIONS perm; +} ; + +/* + * Entry in the securid cache + */ + +struct CACHED_SECURID { + struct CACHED_SECURID *next; + struct CACHED_SECURID *previous; + void *variable; + size_t varsize; + /* above fields must match "struct CACHED_GENERIC" */ + uid_t uid; + gid_t gid; + unsigned int dmode; + le32 securid; +} ; + +/* + * Header of the security cache + * (has no cache structure by itself) + */ + +struct CACHED_PERMISSIONS_HEADER { + unsigned int last; + /* statistics for permissions */ + unsigned long p_writes; + unsigned long p_reads; + unsigned long p_hits; +} ; + +/* + * The whole permissions cache + */ + +struct PERMISSIONS_CACHE { + struct CACHED_PERMISSIONS_HEADER head; + struct CACHED_PERMISSIONS *cachetable[1]; /* array of variable size */ +} ; + +/* + * Security flags values + */ + +enum { + SECURITY_DEFAULT, /* rely on fuse for permissions checking */ + SECURITY_RAW, /* force same ownership/permissions on files */ + SECURITY_ADDSECURIDS, /* upgrade old security descriptors */ + SECURITY_STATICGRPS, /* use static groups for access control */ + SECURITY_WANTED /* a security related option was present */ +} ; + +/* + * Security context, needed by most security functions + */ + +enum { MAPUSERS, MAPGROUPS, MAPCOUNT } ; + +struct SECURITY_CONTEXT { + ntfs_volume *vol; + struct MAPPING *mapping[MAPCOUNT]; + struct PERMISSIONS_CACHE **pseccache; + uid_t uid; /* uid of user requesting (not the mounter) */ + gid_t gid; /* gid of user requesting (not the mounter) */ + pid_t tid; /* thread id of thread requesting */ + mode_t umask; /* umask of requesting thread */ + } ; + +#if POSIXACLS + +/* + * Posix ACL structures + */ + +struct POSIX_ACE { + u16 tag; + u16 perms; + s32 id; +} ; + +struct POSIX_ACL { + u8 version; + u8 flags; + u16 filler; + struct POSIX_ACE ace[0]; +} ; + +struct POSIX_SECURITY { + mode_t mode; + int acccnt; + int defcnt; + int firstdef; + u16 tagsset; + struct POSIX_ACL acl; +} ; + +/* + * Posix tags, cpu-endian 16 bits + */ + +enum { + POSIX_ACL_USER_OBJ = 1, + POSIX_ACL_USER = 2, + POSIX_ACL_GROUP_OBJ = 4, + POSIX_ACL_GROUP = 8, + POSIX_ACL_MASK = 16, + POSIX_ACL_OTHER = 32, + POSIX_ACL_SPECIAL = 64 /* internal use only */ +} ; + +#define POSIX_ACL_EXTENSIONS (POSIX_ACL_USER | POSIX_ACL_GROUP | POSIX_ACL_MASK) + +/* + * Posix permissions, cpu-endian 16 bits + */ + +enum { + POSIX_PERM_X = 1, + POSIX_PERM_W = 2, + POSIX_PERM_R = 4, + POSIX_PERM_DENIAL = 64 /* internal use only */ +} ; + +#define POSIX_VERSION 2 + +#endif + +extern BOOL ntfs_guid_is_zero(const GUID *guid); +extern char *ntfs_guid_to_mbs(const GUID *guid, char *guid_str); + +/** + * ntfs_sid_is_valid - determine if a SID is valid + * @sid: SID for which to determine if it is valid + * + * Determine if the SID pointed to by @sid is valid. + * + * Return TRUE if it is valid and FALSE otherwise. + */ +static __inline__ BOOL ntfs_sid_is_valid(const SID *sid) +{ + if (!sid || sid->revision != SID_REVISION || + sid->sub_authority_count > SID_MAX_SUB_AUTHORITIES) + return FALSE; + return TRUE; +} + +extern int ntfs_sid_to_mbs_size(const SID *sid); +extern char *ntfs_sid_to_mbs(const SID *sid, char *sid_str, + size_t sid_str_size); +extern void ntfs_generate_guid(GUID *guid); +extern int ntfs_sd_add_everyone(ntfs_inode *ni); + +extern le32 ntfs_security_hash(const SECURITY_DESCRIPTOR_RELATIVE *sd, + const u32 len); + +int ntfs_build_mapping(struct SECURITY_CONTEXT *scx, const char *usermap_path); +int ntfs_get_owner_mode(struct SECURITY_CONTEXT *scx, + ntfs_inode *ni, struct stat*); +int ntfs_set_mode(struct SECURITY_CONTEXT *scx, ntfs_inode *ni, mode_t mode); +BOOL ntfs_allowed_as_owner(struct SECURITY_CONTEXT *scx, ntfs_inode *ni); +int ntfs_allowed_access(struct SECURITY_CONTEXT *scx, + ntfs_inode *ni, int accesstype); +BOOL old_ntfs_allowed_dir_access(struct SECURITY_CONTEXT *scx, + const char *path, int accesstype); + +#if POSIXACLS +le32 ntfs_alloc_securid(struct SECURITY_CONTEXT *scx, + uid_t uid, gid_t gid, ntfs_inode *dir_ni, + mode_t mode, BOOL isdir); +#else +le32 ntfs_alloc_securid(struct SECURITY_CONTEXT *scx, + uid_t uid, gid_t gid, mode_t mode, BOOL isdir); +#endif +int ntfs_set_owner(struct SECURITY_CONTEXT *scx, ntfs_inode *ni, + uid_t uid, gid_t gid); +int ntfs_set_ownmod(struct SECURITY_CONTEXT *scx, + ntfs_inode *ni, uid_t uid, gid_t gid, mode_t mode); +#if POSIXACLS +int ntfs_set_owner_mode(struct SECURITY_CONTEXT *scx, + ntfs_inode *ni, uid_t uid, gid_t gid, + mode_t mode, struct POSIX_SECURITY *pxdesc); +#else +int ntfs_set_owner_mode(struct SECURITY_CONTEXT *scx, + ntfs_inode *ni, uid_t uid, gid_t gid, mode_t mode); +#endif +le32 ntfs_inherited_id(struct SECURITY_CONTEXT *scx, + ntfs_inode *dir_ni, BOOL fordir); +int ntfs_open_secure(ntfs_volume *vol); +void ntfs_close_secure(struct SECURITY_CONTEXT *scx); + +#if POSIXACLS + +int ntfs_set_inherited_posix(struct SECURITY_CONTEXT *scx, + ntfs_inode *ni, uid_t uid, gid_t gid, + ntfs_inode *dir_ni, mode_t mode); +int ntfs_get_posix_acl(struct SECURITY_CONTEXT *scx, ntfs_inode *ni, + const char *name, char *value, size_t size); +int ntfs_set_posix_acl(struct SECURITY_CONTEXT *scx, ntfs_inode *ni, + const char *name, const char *value, size_t size, + int flags); +int ntfs_remove_posix_acl(struct SECURITY_CONTEXT *scx, ntfs_inode *ni, + const char *name); +#endif + +int ntfs_get_ntfs_acl(struct SECURITY_CONTEXT *scx, ntfs_inode *ni, + char *value, size_t size); +int ntfs_set_ntfs_acl(struct SECURITY_CONTEXT *scx, ntfs_inode *ni, + const char *value, size_t size, int flags); + +int ntfs_get_ntfs_attrib(ntfs_inode *ni, char *value, size_t size); +int ntfs_set_ntfs_attrib(ntfs_inode *ni, + const char *value, size_t size, int flags); + + +/* + * Security API for direct access to security descriptors + * based on Win32 API + */ + +#define MAGIC_API 0x09042009 + +struct SECURITY_API { + u32 magic; + struct SECURITY_CONTEXT security; + struct PERMISSIONS_CACHE *seccache; +} ; + +/* + * The following constants are used in interfacing external programs. + * They are not to be stored on disk and must be defined in their + * native cpu representation. + * When disk representation (le) is needed, use SE_DACL_PRESENT, etc. + */ +enum { OWNER_SECURITY_INFORMATION = 1, + GROUP_SECURITY_INFORMATION = 2, + DACL_SECURITY_INFORMATION = 4, + SACL_SECURITY_INFORMATION = 8 +} ; + +int ntfs_get_file_security(struct SECURITY_API *scapi, + const char *path, u32 selection, + char *buf, u32 buflen, u32 *psize); +int ntfs_set_file_security(struct SECURITY_API *scapi, + const char *path, u32 selection, const char *attr); +int ntfs_get_file_attributes(struct SECURITY_API *scapi, + const char *path); +BOOL ntfs_set_file_attributes(struct SECURITY_API *scapi, + const char *path, s32 attrib); +BOOL ntfs_read_directory(struct SECURITY_API *scapi, + const char *path, ntfs_filldir_t callback, void *context); +int ntfs_read_sds(struct SECURITY_API *scapi, + char *buf, u32 size, u32 offset); +INDEX_ENTRY *ntfs_read_sii(struct SECURITY_API *scapi, + INDEX_ENTRY *entry); +INDEX_ENTRY *ntfs_read_sdh(struct SECURITY_API *scapi, + INDEX_ENTRY *entry); +struct SECURITY_API *ntfs_initialize_file_security(const char *device, + int flags); +BOOL ntfs_leave_file_security(struct SECURITY_API *scx); + +int ntfs_get_usid(struct SECURITY_API *scapi, uid_t uid, char *buf); +int ntfs_get_gsid(struct SECURITY_API *scapi, gid_t gid, char *buf); +int ntfs_get_user(struct SECURITY_API *scapi, const SID *usid); +int ntfs_get_group(struct SECURITY_API *scapi, const SID *gsid); + +#endif /* defined _NTFS_SECURITY_H */ diff --git a/include/ntfs-3g/support.h b/include/ntfs-3g/support.h new file mode 100755 index 0000000..6af4761 --- a/dev/null +++ b/include/ntfs-3g/support.h @@ -0,0 +1,85 @@ +/* + * support.h - Useful definitions and macros. Originated from the Linux-NTFS project. + * + * Copyright (c) 2000-2004 Anton Altaparmakov + * + * This program/include file 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/include file 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 (in the main directory of the NTFS-3G + * distribution in the file COPYING); if not, write to the Free Software + * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _NTFS_SUPPORT_H +#define _NTFS_SUPPORT_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_STDDEF_H +#include +#endif + +/* + * Our mailing list. Use this define to prevent typos in email address. + */ +#define NTFS_DEV_LIST "ntfs-3g-devel@lists.sf.net" + +/* + * Generic macro to convert pointers to values for comparison purposes. + */ +#ifndef p2n +#define p2n(p) ((ptrdiff_t)((ptrdiff_t*)(p))) +#endif + +/* + * The classic min and max macros. + */ +#ifndef min +#define min(a,b) ((a) <= (b) ? (a) : (b)) +#endif + +#ifndef max +#define max(a,b) ((a) >= (b) ? (a) : (b)) +#endif + +/* + * Useful macro for determining the offset of a struct member. + */ +#ifndef offsetof +#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) +#endif + +/* + * Simple bit operation macros. NOTE: These are NOT atomic. + */ +#define test_bit(bit, var) ((var) & (1 << (bit))) +#define set_bit(bit, var) (var) |= 1 << (bit) +#define clear_bit(bit, var) (var) &= ~(1 << (bit)) + +#define test_and_set_bit(bit, var) \ +({ \ + const BOOL old_state = test_bit(bit, var); \ + set_bit(bit, var); \ + old_state; \ +}) + +#define test_and_clear_bit(bit, var) \ +({ \ + const BOOL old_state = test_bit(bit, var); \ + clear_bit(bit, var); \ + old_state; \ +}) + +#endif /* defined _NTFS_SUPPORT_H */ + diff --git a/include/ntfs-3g/types.h b/include/ntfs-3g/types.h new file mode 100755 index 0000000..8b7f3f5 --- a/dev/null +++ b/include/ntfs-3g/types.h @@ -0,0 +1,124 @@ +/* + * types.h - Misc type definitions not related to on-disk structure. + * Originated from the Linux-NTFS project. + * + * Copyright (c) 2000-2004 Anton Altaparmakov + * + * This program/include file 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/include file 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 (in the main directory of the NTFS-3G + * distribution in the file COPYING); if not, write to the Free Software + * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _NTFS_TYPES_H +#define _NTFS_TYPES_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#if HAVE_STDINT_H || !HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_SYS_TYPES_H +#include +#endif + +typedef uint8_t u8; /* Unsigned types of an exact size */ +typedef uint16_t u16; +typedef uint32_t u32; +typedef uint64_t u64; + +typedef int8_t s8; /* Signed types of an exact size */ +typedef int16_t s16; +typedef int32_t s32; +typedef int64_t s64; + +typedef u16 le16; +typedef u32 le32; +typedef u64 le64; + +/* + * Declare sle{16,32,64} to be unsigned because we do not want sign extension + * on BE architectures. + */ +typedef u16 sle16; +typedef u32 sle32; +typedef u64 sle64; + +typedef u16 ntfschar; /* 2-byte Unicode character type. */ +#define UCHAR_T_SIZE_BITS 1 + +/* + * Clusters are signed 64-bit values on NTFS volumes. We define two types, LCN + * and VCN, to allow for type checking and better code readability. + */ +typedef s64 VCN; +typedef sle64 leVCN; +typedef s64 LCN; +typedef sle64 leLCN; + +/* + * The NTFS journal $LogFile uses log sequence numbers which are signed 64-bit + * values. We define our own type LSN, to allow for type checking and better + * code readability. + */ +typedef s64 LSN; +typedef sle64 leLSN; + +/* + * Cygwin has a collision between our BOOL and 's + * As long as this file will be included after were fine. + */ +#ifndef _WINDEF_H +/** + * enum BOOL - These are just to make the code more readable... + */ +typedef enum { +#ifndef FALSE + FALSE = 0, +#endif +#ifndef NO + NO = 0, +#endif +#ifndef ZERO + ZERO = 0, +#endif +#ifndef TRUE + TRUE = 1, +#endif +#ifndef YES + YES = 1, +#endif +#ifndef ONE + ONE = 1, +#endif +} BOOL; +#endif /* defined _WINDEF_H */ + +/** + * enum IGNORE_CASE_BOOL - + */ +typedef enum { + CASE_SENSITIVE = 0, + IGNORE_CASE = 1, +} IGNORE_CASE_BOOL; + +#define STATUS_OK (0) +#define STATUS_ERROR (-1) +#define STATUS_RESIDENT_ATTRIBUTE_FILLED_MFT (-2) +#define STATUS_KEEP_SEARCHING (-3) +#define STATUS_NOT_FOUND (-4) + +#endif /* defined _NTFS_TYPES_H */ + diff --git a/include/ntfs-3g/unistr.h b/include/ntfs-3g/unistr.h new file mode 100755 index 0000000..5f0b467 --- a/dev/null +++ b/include/ntfs-3g/unistr.h @@ -0,0 +1,116 @@ +/* + * unistr.h - Exports for Unicode string handling. Originated from the Linux-NTFS + * project. + * + * Copyright (c) 2000-2004 Anton Altaparmakov + * + * This program/include file 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/include file 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 (in the main directory of the NTFS-3G + * distribution in the file COPYING); if not, write to the Free Software + * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _NTFS_UNISTR_H +#define _NTFS_UNISTR_H + +#include "types.h" +#include "layout.h" + +extern BOOL ntfs_names_are_equal(const ntfschar *s1, size_t s1_len, + const ntfschar *s2, size_t s2_len, const IGNORE_CASE_BOOL ic, + const ntfschar *upcase, const u32 upcase_size); + +extern int ntfs_names_full_collate(const ntfschar *name1, const u32 name1_len, + const ntfschar *name2, const u32 name2_len, + const IGNORE_CASE_BOOL ic, + const ntfschar *upcase, const u32 upcase_len); + +extern int ntfs_ucsncmp(const ntfschar *s1, const ntfschar *s2, size_t n); + +extern int ntfs_ucsncasecmp(const ntfschar *s1, const ntfschar *s2, size_t n, + const ntfschar *upcase, const u32 upcase_size); + +extern u32 ntfs_ucsnlen(const ntfschar *s, u32 maxlen); + +extern ntfschar *ntfs_ucsndup(const ntfschar *s, u32 maxlen); + +extern void ntfs_name_upcase(ntfschar *name, u32 name_len, + const ntfschar *upcase, const u32 upcase_len); + +extern void ntfs_file_value_upcase(FILE_NAME_ATTR *file_name_attr, + const ntfschar *upcase, const u32 upcase_len); + +extern int ntfs_file_values_compare(const FILE_NAME_ATTR *file_name_attr1, + const FILE_NAME_ATTR *file_name_attr2, + const int err_val, const IGNORE_CASE_BOOL ic, + const ntfschar *upcase, const u32 upcase_len); + +extern int ntfs_ucstombs(const ntfschar *ins, const int ins_len, char **outs, + int outs_len); +extern int ntfs_mbstoucs(const char *ins, ntfschar **outs); + +extern void ntfs_upcase_table_build(ntfschar *uc, u32 uc_len); + +extern ntfschar *ntfs_str2ucs(const char *s, int *len); + +extern void ntfs_ucsfree(ntfschar *ucs); + +extern BOOL ntfs_forbidden_chars(const ntfschar *name, int len); +extern BOOL ntfs_collapsible_chars(ntfs_volume *vol, + const ntfschar *shortname, int shortlen, + const ntfschar *longname, int longlen); + +extern int ntfs_set_char_encoding(const char *locale); + +#if defined(__APPLE__) || defined(__DARWIN__) +/** + * Mac OS X only. + * + * Sets file name Unicode normalization form conversion on or off. + * normalize=0 : Off + * normalize=1 : On + * If set to on, all filenames returned by ntfs-3g will be converted to the NFD + * normalization form, while all filenames recieved by ntfs-3g will be converted to the NFC + * normalization form. Since Windows and most other OS:es use the NFC form while Mac OS X + * mostly uses NFD, this conversion increases compatibility between Mac applications and + * NTFS-3G. + * + * @param normalize decides whether or not the string functions will do automatic filename + * normalization when converting to and from UTF-8. 0 means normalization is disabled, + * 1 means it is enabled. + * @return -1 if the argument was invalid or an error occurred, 0 if all went well. + */ +extern int ntfs_macosx_normalize_filenames(int normalize); + +/** + * Mac OS X only. + * + * Normalizes the input string "utf8_string" to one of the normalization forms NFD or NFC. + * The parameter "composed" decides whether output should be in composed, NFC, form + * (composed == 1) or decomposed, NFD, form (composed == 0). + * Input is assumed to be properly UTF-8 encoded and null-terminated. Output will be a newly + * ntfs_calloc'ed string encoded in UTF-8. It is the callers responsibility to free(...) the + * allocated string when it's no longer needed. + * + * @param utf8_string the input string, which may be in any normalization form. + * @param target a pointer where the resulting string will be stored. + * @param composed decides which composition form to normalize the input string to. 0 means + * composed form (NFC), 1 means decomposed form (NFD). + * @return -1 if the normalization failed for some reason, otherwise the length of the + * normalized string stored in target. + */ +extern int ntfs_macosx_normalize_utf8(const char *utf8_string, char **target, int composed); +#endif /* defined(__APPLE__) || defined(__DARWIN__) */ + +#endif /* defined _NTFS_UNISTR_H */ + diff --git a/include/ntfs-3g/volume.h b/include/ntfs-3g/volume.h new file mode 100755 index 0000000..253e482 --- a/dev/null +++ b/include/ntfs-3g/volume.h @@ -0,0 +1,277 @@ +/* + * volume.h - Exports for NTFS volume handling. Originated from the Linux-NTFS project. + * + * Copyright (c) 2000-2004 Anton Altaparmakov + * Copyright (c) 2004-2005 Richard Russon + * Copyright (c) 2005-2006 Yura Pakhuchiy + * Copyright (c) 2005-2009 Szabolcs Szakacsits + * + * This program/include file 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/include file 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 (in the main directory of the NTFS-3G + * distribution in the file COPYING); if not, write to the Free Software + * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _NTFS_VOLUME_H +#define _NTFS_VOLUME_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_STDIO_H +#include +#endif +#ifdef HAVE_SYS_PARAM_H +#include +#endif +#ifdef HAVE_SYS_MOUNT_H +#include +#endif +#ifdef HAVE_MNTENT_H +#include +#endif + +/* + * Under Cygwin, DJGPP and FreeBSD we do not have MS_RDONLY, + * so we define them ourselves. + */ +#ifndef MS_RDONLY +#define MS_RDONLY 1 +#endif + +#define MS_EXCLUSIVE 0x08000000 + +#ifndef MS_RECOVER +#define MS_RECOVER 0x10000000 +#endif + +#define MS_IGNORE_HIBERFILE 0x20000000 + +/* Forward declaration */ +typedef struct _ntfs_volume ntfs_volume; + +#include "param.h" +#include "types.h" +#include "support.h" +#include "device.h" +#include "inode.h" +#include "attrib.h" +#include "index.h" + +/** + * enum ntfs_mount_flags - + * + * Flags returned by the ntfs_check_if_mounted() function. + */ +typedef enum { + NTFS_MF_MOUNTED = 1, /* Device is mounted. */ + NTFS_MF_ISROOT = 2, /* Device is mounted as system root. */ + NTFS_MF_READONLY = 4, /* Device is mounted read-only. */ +} ntfs_mount_flags; + +extern int ntfs_check_if_mounted(const char *file, unsigned long *mnt_flags); + +typedef enum { + NTFS_VOLUME_OK = 0, + NTFS_VOLUME_SYNTAX_ERROR = 11, + NTFS_VOLUME_NOT_NTFS = 12, + NTFS_VOLUME_CORRUPT = 13, + NTFS_VOLUME_HIBERNATED = 14, + NTFS_VOLUME_UNCLEAN_UNMOUNT = 15, + NTFS_VOLUME_LOCKED = 16, + NTFS_VOLUME_RAID = 17, + NTFS_VOLUME_UNKNOWN_REASON = 18, + NTFS_VOLUME_NO_PRIVILEGE = 19, + NTFS_VOLUME_OUT_OF_MEMORY = 20, + NTFS_VOLUME_FUSE_ERROR = 21, + NTFS_VOLUME_INSECURE = 22 +} ntfs_volume_status; + +/** + * enum ntfs_volume_state_bits - + * + * Defined bits for the state field in the ntfs_volume structure. + */ +typedef enum { + NV_ReadOnly, /* 1: Volume is read-only. */ + NV_CaseSensitive, /* 1: Volume is mounted case-sensitive. */ + NV_LogFileEmpty, /* 1: $logFile journal is empty. */ +} ntfs_volume_state_bits; + +#define test_nvol_flag(nv, flag) test_bit(NV_##flag, (nv)->state) +#define set_nvol_flag(nv, flag) set_bit(NV_##flag, (nv)->state) +#define clear_nvol_flag(nv, flag) clear_bit(NV_##flag, (nv)->state) + +#define NVolReadOnly(nv) test_nvol_flag(nv, ReadOnly) +#define NVolSetReadOnly(nv) set_nvol_flag(nv, ReadOnly) +#define NVolClearReadOnly(nv) clear_nvol_flag(nv, ReadOnly) + +#define NVolCaseSensitive(nv) test_nvol_flag(nv, CaseSensitive) +#define NVolSetCaseSensitive(nv) set_nvol_flag(nv, CaseSensitive) +#define NVolClearCaseSensitive(nv) clear_nvol_flag(nv, CaseSensitive) + +#define NVolLogFileEmpty(nv) test_nvol_flag(nv, LogFileEmpty) +#define NVolSetLogFileEmpty(nv) set_nvol_flag(nv, LogFileEmpty) +#define NVolClearLogFileEmpty(nv) clear_nvol_flag(nv, LogFileEmpty) + +/* + * NTFS version 1.1 and 1.2 are used by Windows NT4. + * NTFS version 2.x is used by Windows 2000 Beta + * NTFS version 3.0 is used by Windows 2000. + * NTFS version 3.1 is used by Windows XP, 2003 and Vista. + */ + +#define NTFS_V1_1(major, minor) ((major) == 1 && (minor) == 1) +#define NTFS_V1_2(major, minor) ((major) == 1 && (minor) == 2) +#define NTFS_V2_X(major, minor) ((major) == 2) +#define NTFS_V3_0(major, minor) ((major) == 3 && (minor) == 0) +#define NTFS_V3_1(major, minor) ((major) == 3 && (minor) == 1) + +#define NTFS_BUF_SIZE 8192 + +/** + * struct _ntfs_volume - structure describing an open volume in memory. + */ +struct _ntfs_volume { + union { + struct ntfs_device *dev; /* NTFS device associated with + the volume. */ + void *sb; /* For kernel porting compatibility. */ + }; + char *vol_name; /* Name of the volume. */ + unsigned long state; /* NTFS specific flags describing this volume. + See ntfs_volume_state_bits above. */ + + ntfs_inode *vol_ni; /* ntfs_inode structure for FILE_Volume. */ + u8 major_ver; /* Ntfs major version of volume. */ + u8 minor_ver; /* Ntfs minor version of volume. */ + le16 flags; /* Bit array of VOLUME_* flags. */ + + u16 sector_size; /* Byte size of a sector. */ + u8 sector_size_bits; /* Log(2) of the byte size of a sector. */ + u32 cluster_size; /* Byte size of a cluster. */ + u32 mft_record_size; /* Byte size of a mft record. */ + u32 indx_record_size; /* Byte size of a INDX record. */ + u8 cluster_size_bits; /* Log(2) of the byte size of a cluster. */ + u8 mft_record_size_bits;/* Log(2) of the byte size of a mft record. */ + u8 indx_record_size_bits;/* Log(2) of the byte size of a INDX record. */ + + /* Variables used by the cluster and mft allocators. */ + u8 mft_zone_multiplier; /* Initial mft zone multiplier. */ + u8 full_zones; /* cluster zones which are full */ + s64 mft_data_pos; /* Mft record number at which to allocate the + next mft record. */ + LCN mft_zone_start; /* First cluster of the mft zone. */ + LCN mft_zone_end; /* First cluster beyond the mft zone. */ + LCN mft_zone_pos; /* Current position in the mft zone. */ + LCN data1_zone_pos; /* Current position in the first data zone. */ + LCN data2_zone_pos; /* Current position in the second data zone. */ + + s64 nr_clusters; /* Volume size in clusters, hence also the + number of bits in lcn_bitmap. */ + ntfs_inode *lcnbmp_ni; /* ntfs_inode structure for FILE_Bitmap. */ + ntfs_attr *lcnbmp_na; /* ntfs_attr structure for the data attribute + of FILE_Bitmap. Each bit represents a + cluster on the volume, bit 0 representing + lcn 0 and so on. A set bit means that the + cluster and vice versa. */ + + LCN mft_lcn; /* Logical cluster number of the data attribute + for FILE_MFT. */ + ntfs_inode *mft_ni; /* ntfs_inode structure for FILE_MFT. */ + ntfs_attr *mft_na; /* ntfs_attr structure for the data attribute + of FILE_MFT. */ + ntfs_attr *mftbmp_na; /* ntfs_attr structure for the bitmap attribute + of FILE_MFT. Each bit represents an mft + record in the $DATA attribute, bit 0 + representing mft record 0 and so on. A set + bit means that the mft record is in use and + vice versa. */ + + ntfs_inode *secure_ni; /* ntfs_inode structure for FILE $Secure */ + ntfs_index_context *secure_xsii; /* index for using $Secure:$SII */ + ntfs_index_context *secure_xsdh; /* index for using $Secure:$SDH */ + int secure_reentry; /* check for non-rentries */ + unsigned int secure_flags; /* flags, see security.h for values */ + + int mftmirr_size; /* Size of the FILE_MFTMirr in mft records. */ + LCN mftmirr_lcn; /* Logical cluster number of the data attribute + for FILE_MFTMirr. */ + ntfs_inode *mftmirr_ni; /* ntfs_inode structure for FILE_MFTMirr. */ + ntfs_attr *mftmirr_na; /* ntfs_attr structure for the data attribute + of FILE_MFTMirr. */ + + ntfschar *upcase; /* Upper case equivalents of all 65536 2-byte + Unicode characters. Obtained from + FILE_UpCase. */ + u32 upcase_len; /* Length in Unicode characters of the upcase + table. */ + + ATTR_DEF *attrdef; /* Attribute definitions. Obtained from + FILE_AttrDef. */ + s32 attrdef_len; /* Size of the attribute definition table in + bytes. */ + + s64 free_clusters; /* Track the number of free clusters which + greatly improves statfs() performance */ + s64 free_mft_records; /* Same for free mft records (see above) */ + BOOL efs_raw; /* volume is mounted for raw access to + efs-encrypted files */ + +#if CACHE_INODE_SIZE + struct CACHE_HEADER *xinode_cache; +#endif +#if CACHE_NIDATA_SIZE + struct CACHE_HEADER *nidata_cache; +#endif +#if CACHE_LOOKUP_SIZE + struct CACHE_HEADER *lookup_cache; +#endif +#if CACHE_SECURID_SIZE + struct CACHE_HEADER *securid_cache; +#endif +#if CACHE_LEGACY_SIZE + struct CACHE_HEADER *legacy_cache; +#endif + +}; + +extern const char *ntfs_home; + +extern ntfs_volume *ntfs_volume_alloc(void); + +extern ntfs_volume *ntfs_volume_startup(struct ntfs_device *dev, + unsigned long flags); + +extern ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, + unsigned long flags); + +extern ntfs_volume *ntfs_mount(const char *name, unsigned long flags); +extern int ntfs_umount(ntfs_volume *vol, const BOOL force); + +extern int ntfs_version_is_supported(ntfs_volume *vol); +extern int ntfs_volume_check_hiberfile(ntfs_volume *vol, int verbose); +extern int ntfs_logfile_reset(ntfs_volume *vol); + +extern int ntfs_volume_write_flags(ntfs_volume *vol, const le16 flags); + +extern int ntfs_volume_error(int err); +extern void ntfs_mount_error(const char *vol, const char *mntpoint, int err); + +extern int ntfs_volume_get_free_space(ntfs_volume *vol); + +extern int ntfs_set_locale(void); + +#endif /* defined _NTFS_VOLUME_H */ + diff --git a/install-sh b/install-sh new file mode 100755 index 0000000..a5897de --- a/dev/null +++ b/install-sh @@ -0,0 +1,519 @@ +#!/bin/sh +# install - install a program, script, or datafile + +scriptversion=2006-12-25.00 + +# 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. + +nl=' +' +IFS=" "" $nl" + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit=${DOITPROG-} +if test -z "$doit"; then + doit_exec=exec +else + doit_exec=$doit +fi + +# 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_glob='?' +initialize_posix_glob=' + test "$posix_glob" != "?" || { + if (set -f) 2>/dev/null; then + posix_glob= + else + posix_glob=: + fi + } +' + +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 +no_target_directory= + +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 + *' '* | *' '* | *' +'* | *'*'* | *'?'* | *'['*) + echo "$0: invalid mode: $mode" >&2 + exit 1;; + esac + shift;; + + -o) chowncmd="$chownprog $2" + shift;; + + -s) stripcmd=$stripprog;; + + -t) dst_arg=$2 + shift;; + + -T) no_target_directory=true;; + + --version) echo "$0 $scriptversion"; exit $?;; + + --) shift + break;; + + -*) echo "$0: invalid option: $1" >&2 + exit 1;; + + *) break;; + esac + shift +done + +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 + 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 + trap '(exit $?); exit' 1 2 13 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 starting with `-'. + 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 + # Protect names starting with `-'. + case $dst in + -*) dst=./$dst;; + esac + + # 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 -n "$no_target_directory"; then + echo "$0: $dst_arg: Is a directory" >&2 + exit 1 + fi + dstdir=$dst + dst=$dstdir/`basename "$src"` + dstdir_status=0 + else + # Prefer dirname, but fall back on a substitute if dirname fails. + dstdir=` + (dirname "$dst") 2>/dev/null || + expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$dst" : 'X\(//\)[^/]' \| \ + X"$dst" : 'X\(//\)$' \| \ + X"$dst" : 'X\(/\)' \| . 2>/dev/null || + echo X"$dst" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q' + ` + + 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-writeable 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 + + eval "$initialize_posix_glob" + + oIFS=$IFS + IFS=/ + $posix_glob set -f + set fnord $dstdir + shift + $posix_glob set +f + IFS=$oIFS + + prefixes= + + for d + do + test -z "$d" && 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` && + + eval "$initialize_posix_glob" && + $posix_glob set -f && + set X $old && old=:$2:$4:$5:$6 && + set X $new && new=:$2:$4:$5:$6 && + $posix_glob 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-end: "$" +# End: diff --git a/libfuse-lite/Makefile.am b/libfuse-lite/Makefile.am new file mode 100755 index 0000000..c09e8d7 --- a/dev/null +++ b/libfuse-lite/Makefile.am @@ -0,0 +1,28 @@ + +MAINTAINERCLEANFILES = $(srcdir)/Makefile.in + +if FUSE_INTERNAL +noinst_LTLIBRARIES = libfuse-lite.la +endif + +libfuse_lite_la_CFLAGS= \ + $(AM_CFLAGS) \ + -I$(top_srcdir)/include/fuse-lite + +libfuse_lite_la_LIBADD = $(LIBFUSE_LITE_LIBS) + +libfuse_lite_la_SOURCES = \ + fuse.c \ + fuse_i.h \ + fuse_kern_chan.c \ + fuse_loop.c \ + fuse_lowlevel.c \ + fuse_misc.h \ + fuse_opt.c \ + fuse_session.c \ + fuse_signals.c \ + fusermount.c \ + helper.c \ + mount.c \ + mount_util.c \ + mount_util.h diff --git a/libfuse-lite/Makefile.in b/libfuse-lite/Makefile.in new file mode 100755 index 0000000..155b477 --- a/dev/null +++ b/libfuse-lite/Makefile.in @@ -0,0 +1,572 @@ +# Makefile.in generated by automake 1.10.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008 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@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@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 = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +subdir = libfuse-lite +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +LTLIBRARIES = $(noinst_LTLIBRARIES) +am__DEPENDENCIES_1 = +libfuse_lite_la_DEPENDENCIES = $(am__DEPENDENCIES_1) +am_libfuse_lite_la_OBJECTS = libfuse_lite_la-fuse.lo \ + libfuse_lite_la-fuse_kern_chan.lo libfuse_lite_la-fuse_loop.lo \ + libfuse_lite_la-fuse_lowlevel.lo libfuse_lite_la-fuse_opt.lo \ + libfuse_lite_la-fuse_session.lo \ + libfuse_lite_la-fuse_signals.lo libfuse_lite_la-fusermount.lo \ + libfuse_lite_la-helper.lo libfuse_lite_la-mount.lo \ + libfuse_lite_la-mount_util.lo +libfuse_lite_la_OBJECTS = $(am_libfuse_lite_la_OBJECTS) +libfuse_lite_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(libfuse_lite_la_CFLAGS) \ + $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +@FUSE_INTERNAL_TRUE@am_libfuse_lite_la_rpath = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(libfuse_lite_la_SOURCES) +DIST_SOURCES = $(libfuse_lite_la_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DSYMUTIL = @DSYMUTIL@ +ECHO = @ECHO@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +F77 = @F77@ +FFLAGS = @FFLAGS@ +FUSE_MODULE_CFLAGS = @FUSE_MODULE_CFLAGS@ +FUSE_MODULE_LIBS = @FUSE_MODULE_LIBS@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDCONFIG = @LDCONFIG@ +LDFLAGS = @LDFLAGS@ +LIBFUSE_LITE_LIBS = @LIBFUSE_LITE_LIBS@ +LIBNTFS_3G_VERSION = @LIBNTFS_3G_VERSION@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MV = @MV@ +NMEDIT = @NMEDIT@ +OBJEXT = @OBJEXT@ +OUTPUT_FORMAT = @OUTPUT_FORMAT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PKG_CONFIG = @PKG_CONFIG@ +RANLIB = @RANLIB@ +RM = @RM@ +SED = @SED@ +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_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_F77 = @ac_ct_F77@ +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 = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +ntfs3gincludedir = @ntfs3gincludedir@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgconfigdir = @pkgconfigdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +rootbindir = @rootbindir@ +rootlibdir = @rootlibdir@ +rootsbindir = @rootsbindir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +MAINTAINERCLEANFILES = $(srcdir)/Makefile.in +@FUSE_INTERNAL_TRUE@noinst_LTLIBRARIES = libfuse-lite.la +libfuse_lite_la_CFLAGS = \ + $(AM_CFLAGS) \ + -I$(top_srcdir)/include/fuse-lite + +libfuse_lite_la_LIBADD = $(LIBFUSE_LITE_LIBS) +libfuse_lite_la_SOURCES = \ + fuse.c \ + fuse_i.h \ + fuse_kern_chan.c \ + fuse_loop.c \ + fuse_lowlevel.c \ + fuse_misc.h \ + fuse_opt.c \ + fuse_session.c \ + fuse_signals.c \ + fusermount.c \ + helper.c \ + mount.c \ + mount_util.c \ + mount_util.h + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu libfuse-lite/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu libfuse-lite/Makefile +.PRECIOUS: 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__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libfuse-lite.la: $(libfuse_lite_la_OBJECTS) $(libfuse_lite_la_DEPENDENCIES) + $(libfuse_lite_la_LINK) $(am_libfuse_lite_la_rpath) $(libfuse_lite_la_OBJECTS) $(libfuse_lite_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libfuse_lite_la-fuse.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libfuse_lite_la-fuse_kern_chan.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libfuse_lite_la-fuse_loop.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libfuse_lite_la-fuse_lowlevel.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libfuse_lite_la-fuse_opt.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libfuse_lite_la-fuse_session.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libfuse_lite_la-fuse_signals.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libfuse_lite_la-fusermount.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libfuse_lite_la-helper.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libfuse_lite_la-mount.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libfuse_lite_la-mount_util.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +libfuse_lite_la-fuse.lo: fuse.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libfuse_lite_la_CFLAGS) $(CFLAGS) -MT libfuse_lite_la-fuse.lo -MD -MP -MF $(DEPDIR)/libfuse_lite_la-fuse.Tpo -c -o libfuse_lite_la-fuse.lo `test -f 'fuse.c' || echo '$(srcdir)/'`fuse.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libfuse_lite_la-fuse.Tpo $(DEPDIR)/libfuse_lite_la-fuse.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='fuse.c' object='libfuse_lite_la-fuse.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libfuse_lite_la_CFLAGS) $(CFLAGS) -c -o libfuse_lite_la-fuse.lo `test -f 'fuse.c' || echo '$(srcdir)/'`fuse.c + +libfuse_lite_la-fuse_kern_chan.lo: fuse_kern_chan.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libfuse_lite_la_CFLAGS) $(CFLAGS) -MT libfuse_lite_la-fuse_kern_chan.lo -MD -MP -MF $(DEPDIR)/libfuse_lite_la-fuse_kern_chan.Tpo -c -o libfuse_lite_la-fuse_kern_chan.lo `test -f 'fuse_kern_chan.c' || echo '$(srcdir)/'`fuse_kern_chan.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libfuse_lite_la-fuse_kern_chan.Tpo $(DEPDIR)/libfuse_lite_la-fuse_kern_chan.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='fuse_kern_chan.c' object='libfuse_lite_la-fuse_kern_chan.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libfuse_lite_la_CFLAGS) $(CFLAGS) -c -o libfuse_lite_la-fuse_kern_chan.lo `test -f 'fuse_kern_chan.c' || echo '$(srcdir)/'`fuse_kern_chan.c + +libfuse_lite_la-fuse_loop.lo: fuse_loop.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libfuse_lite_la_CFLAGS) $(CFLAGS) -MT libfuse_lite_la-fuse_loop.lo -MD -MP -MF $(DEPDIR)/libfuse_lite_la-fuse_loop.Tpo -c -o libfuse_lite_la-fuse_loop.lo `test -f 'fuse_loop.c' || echo '$(srcdir)/'`fuse_loop.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libfuse_lite_la-fuse_loop.Tpo $(DEPDIR)/libfuse_lite_la-fuse_loop.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='fuse_loop.c' object='libfuse_lite_la-fuse_loop.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libfuse_lite_la_CFLAGS) $(CFLAGS) -c -o libfuse_lite_la-fuse_loop.lo `test -f 'fuse_loop.c' || echo '$(srcdir)/'`fuse_loop.c + +libfuse_lite_la-fuse_lowlevel.lo: fuse_lowlevel.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libfuse_lite_la_CFLAGS) $(CFLAGS) -MT libfuse_lite_la-fuse_lowlevel.lo -MD -MP -MF $(DEPDIR)/libfuse_lite_la-fuse_lowlevel.Tpo -c -o libfuse_lite_la-fuse_lowlevel.lo `test -f 'fuse_lowlevel.c' || echo '$(srcdir)/'`fuse_lowlevel.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libfuse_lite_la-fuse_lowlevel.Tpo $(DEPDIR)/libfuse_lite_la-fuse_lowlevel.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='fuse_lowlevel.c' object='libfuse_lite_la-fuse_lowlevel.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libfuse_lite_la_CFLAGS) $(CFLAGS) -c -o libfuse_lite_la-fuse_lowlevel.lo `test -f 'fuse_lowlevel.c' || echo '$(srcdir)/'`fuse_lowlevel.c + +libfuse_lite_la-fuse_opt.lo: fuse_opt.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libfuse_lite_la_CFLAGS) $(CFLAGS) -MT libfuse_lite_la-fuse_opt.lo -MD -MP -MF $(DEPDIR)/libfuse_lite_la-fuse_opt.Tpo -c -o libfuse_lite_la-fuse_opt.lo `test -f 'fuse_opt.c' || echo '$(srcdir)/'`fuse_opt.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libfuse_lite_la-fuse_opt.Tpo $(DEPDIR)/libfuse_lite_la-fuse_opt.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='fuse_opt.c' object='libfuse_lite_la-fuse_opt.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libfuse_lite_la_CFLAGS) $(CFLAGS) -c -o libfuse_lite_la-fuse_opt.lo `test -f 'fuse_opt.c' || echo '$(srcdir)/'`fuse_opt.c + +libfuse_lite_la-fuse_session.lo: fuse_session.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libfuse_lite_la_CFLAGS) $(CFLAGS) -MT libfuse_lite_la-fuse_session.lo -MD -MP -MF $(DEPDIR)/libfuse_lite_la-fuse_session.Tpo -c -o libfuse_lite_la-fuse_session.lo `test -f 'fuse_session.c' || echo '$(srcdir)/'`fuse_session.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libfuse_lite_la-fuse_session.Tpo $(DEPDIR)/libfuse_lite_la-fuse_session.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='fuse_session.c' object='libfuse_lite_la-fuse_session.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libfuse_lite_la_CFLAGS) $(CFLAGS) -c -o libfuse_lite_la-fuse_session.lo `test -f 'fuse_session.c' || echo '$(srcdir)/'`fuse_session.c + +libfuse_lite_la-fuse_signals.lo: fuse_signals.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libfuse_lite_la_CFLAGS) $(CFLAGS) -MT libfuse_lite_la-fuse_signals.lo -MD -MP -MF $(DEPDIR)/libfuse_lite_la-fuse_signals.Tpo -c -o libfuse_lite_la-fuse_signals.lo `test -f 'fuse_signals.c' || echo '$(srcdir)/'`fuse_signals.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libfuse_lite_la-fuse_signals.Tpo $(DEPDIR)/libfuse_lite_la-fuse_signals.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='fuse_signals.c' object='libfuse_lite_la-fuse_signals.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libfuse_lite_la_CFLAGS) $(CFLAGS) -c -o libfuse_lite_la-fuse_signals.lo `test -f 'fuse_signals.c' || echo '$(srcdir)/'`fuse_signals.c + +libfuse_lite_la-fusermount.lo: fusermount.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libfuse_lite_la_CFLAGS) $(CFLAGS) -MT libfuse_lite_la-fusermount.lo -MD -MP -MF $(DEPDIR)/libfuse_lite_la-fusermount.Tpo -c -o libfuse_lite_la-fusermount.lo `test -f 'fusermount.c' || echo '$(srcdir)/'`fusermount.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libfuse_lite_la-fusermount.Tpo $(DEPDIR)/libfuse_lite_la-fusermount.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='fusermount.c' object='libfuse_lite_la-fusermount.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libfuse_lite_la_CFLAGS) $(CFLAGS) -c -o libfuse_lite_la-fusermount.lo `test -f 'fusermount.c' || echo '$(srcdir)/'`fusermount.c + +libfuse_lite_la-helper.lo: helper.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libfuse_lite_la_CFLAGS) $(CFLAGS) -MT libfuse_lite_la-helper.lo -MD -MP -MF $(DEPDIR)/libfuse_lite_la-helper.Tpo -c -o libfuse_lite_la-helper.lo `test -f 'helper.c' || echo '$(srcdir)/'`helper.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libfuse_lite_la-helper.Tpo $(DEPDIR)/libfuse_lite_la-helper.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='helper.c' object='libfuse_lite_la-helper.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libfuse_lite_la_CFLAGS) $(CFLAGS) -c -o libfuse_lite_la-helper.lo `test -f 'helper.c' || echo '$(srcdir)/'`helper.c + +libfuse_lite_la-mount.lo: mount.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libfuse_lite_la_CFLAGS) $(CFLAGS) -MT libfuse_lite_la-mount.lo -MD -MP -MF $(DEPDIR)/libfuse_lite_la-mount.Tpo -c -o libfuse_lite_la-mount.lo `test -f 'mount.c' || echo '$(srcdir)/'`mount.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libfuse_lite_la-mount.Tpo $(DEPDIR)/libfuse_lite_la-mount.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='mount.c' object='libfuse_lite_la-mount.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libfuse_lite_la_CFLAGS) $(CFLAGS) -c -o libfuse_lite_la-mount.lo `test -f 'mount.c' || echo '$(srcdir)/'`mount.c + +libfuse_lite_la-mount_util.lo: mount_util.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libfuse_lite_la_CFLAGS) $(CFLAGS) -MT libfuse_lite_la-mount_util.lo -MD -MP -MF $(DEPDIR)/libfuse_lite_la-mount_util.Tpo -c -o libfuse_lite_la-mount_util.lo `test -f 'mount_util.c' || echo '$(srcdir)/'`mount_util.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libfuse_lite_la-mount_util.Tpo $(DEPDIR)/libfuse_lite_la-mount_util.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='mount_util.c' object='libfuse_lite_la-mount_util.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libfuse_lite_la_CFLAGS) $(CFLAGS) -c -o libfuse_lite_la-mount_util.lo `test -f 'mount_util.c' || echo '$(srcdir)/'`mount_util.c + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(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 $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$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 $(LTLIBRARIES) +installdirs: +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: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +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 + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstLTLIBRARIES ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + 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-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags uninstall uninstall-am + +# 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: diff --git a/libfuse-lite/fuse.c b/libfuse-lite/fuse.c new file mode 100755 index 0000000..0e81738 --- a/dev/null +++ b/libfuse-lite/fuse.c @@ -0,0 +1,2789 @@ +/* + FUSE: Filesystem in Userspace + Copyright (C) 2001-2007 Miklos Szeredi + + This program can be distributed under the terms of the GNU LGPLv2. + See the file COPYING.LIB +*/ + +#include "config.h" +#include "fuse_i.h" +#include "fuse_lowlevel.h" +#include "fuse_opt.h" +#include "fuse_misc.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define FUSE_DEFAULT_INTR_SIGNAL SIGUSR1 + +#define FUSE_UNKNOWN_INO 0xffffffff +#define OFFSET_MAX 0x7fffffffffffffffLL + +struct fuse_config { + unsigned int uid; + unsigned int gid; + unsigned int umask; + double entry_timeout; + double negative_timeout; + double attr_timeout; + double ac_attr_timeout; + int ac_attr_timeout_set; + int debug; + int hard_remove; + int use_ino; + int readdir_ino; + int set_mode; + int set_uid; + int set_gid; + int direct_io; + int kernel_cache; + int intr; + int intr_signal; + int help; +}; + +struct fuse_fs { + struct fuse_operations op; + void *user_data; +}; + +struct fuse { + struct fuse_session *se; + struct node **name_table; + size_t name_table_size; + struct node **id_table; + size_t id_table_size; + fuse_ino_t ctr; + unsigned int generation; + unsigned int hidectr; + pthread_mutex_t lock; + pthread_rwlock_t tree_lock; + struct fuse_config conf; + int intr_installed; + struct fuse_fs *fs; + int utime_omit_ok; +}; + +struct lock { + int type; + off_t start; + off_t end; + pid_t pid; + uint64_t owner; + struct lock *next; +}; + +struct node { + struct node *name_next; + struct node *id_next; + fuse_ino_t nodeid; + unsigned int generation; + int refctr; + struct node *parent; + char *name; + uint64_t nlookup; + int open_count; + int is_hidden; + struct lock *locks; +}; + +struct fuse_dh { + pthread_mutex_t lock; + struct fuse *fuse; + fuse_req_t req; + char *contents; + int allocated; + unsigned len; + unsigned size; + unsigned needlen; + int filled; + uint64_t fh; + int error; + fuse_ino_t nodeid; +}; + +struct fuse_context_i { + struct fuse_context ctx; + fuse_req_t req; +}; + +static pthread_key_t fuse_context_key; +static pthread_mutex_t fuse_context_lock = PTHREAD_MUTEX_INITIALIZER; +static int fuse_context_ref; + +static struct node *get_node_nocheck(struct fuse *f, fuse_ino_t nodeid) +{ + size_t hash = nodeid % f->id_table_size; + struct node *node; + + for (node = f->id_table[hash]; node != NULL; node = node->id_next) + if (node->nodeid == nodeid) + return node; + + return NULL; +} + +static struct node *get_node(struct fuse *f, fuse_ino_t nodeid) +{ + struct node *node = get_node_nocheck(f, nodeid); + if (!node) { + fprintf(stderr, "fuse internal error: node %llu not found\n", + (unsigned long long) nodeid); + abort(); + } + return node; +} + +static void free_node(struct node *node) +{ + free(node->name); + free(node); +} + +static void unhash_id(struct fuse *f, struct node *node) +{ + size_t hash = node->nodeid % f->id_table_size; + struct node **nodep = &f->id_table[hash]; + + for (; *nodep != NULL; nodep = &(*nodep)->id_next) + if (*nodep == node) { + *nodep = node->id_next; + return; + } +} + +static void hash_id(struct fuse *f, struct node *node) +{ + size_t hash = node->nodeid % f->id_table_size; + node->id_next = f->id_table[hash]; + f->id_table[hash] = node; +} + +static unsigned int name_hash(struct fuse *f, fuse_ino_t parent, + const char *name) +{ + unsigned int hash = *name; + + if (hash) + for (name += 1; *name != '\0'; name++) + hash = (hash << 5) - hash + *name; + + return (hash + parent) % f->name_table_size; +} + +static void unref_node(struct fuse *f, struct node *node); + +static void unhash_name(struct fuse *f, struct node *node) +{ + if (node->name) { + size_t hash = name_hash(f, node->parent->nodeid, node->name); + struct node **nodep = &f->name_table[hash]; + + for (; *nodep != NULL; nodep = &(*nodep)->name_next) + if (*nodep == node) { + *nodep = node->name_next; + node->name_next = NULL; + unref_node(f, node->parent); + free(node->name); + node->name = NULL; + node->parent = NULL; + return; + } + fprintf(stderr, "fuse internal error: unable to unhash node: %llu\n", + (unsigned long long) node->nodeid); + abort(); + } +} + +static int hash_name(struct fuse *f, struct node *node, fuse_ino_t parentid, + const char *name) +{ + size_t hash = name_hash(f, parentid, name); + struct node *parent = get_node(f, parentid); + node->name = strdup(name); + if (node->name == NULL) + return -1; + + parent->refctr ++; + node->parent = parent; + node->name_next = f->name_table[hash]; + f->name_table[hash] = node; + return 0; +} + +static void delete_node(struct fuse *f, struct node *node) +{ + if (f->conf.debug) + fprintf(stderr, "delete: %llu\n", (unsigned long long) node->nodeid); + + assert(!node->name); + unhash_id(f, node); + free_node(node); +} + +static void unref_node(struct fuse *f, struct node *node) +{ + assert(node->refctr > 0); + node->refctr --; + if (!node->refctr) + delete_node(f, node); +} + +static fuse_ino_t next_id(struct fuse *f) +{ + do { + f->ctr = (f->ctr + 1) & 0xffffffff; + if (!f->ctr) + f->generation ++; + } while (f->ctr == 0 || f->ctr == FUSE_UNKNOWN_INO || + get_node_nocheck(f, f->ctr) != NULL); + return f->ctr; +} + +static struct node *lookup_node(struct fuse *f, fuse_ino_t parent, + const char *name) +{ + size_t hash = name_hash(f, parent, name); + struct node *node; + + for (node = f->name_table[hash]; node != NULL; node = node->name_next) + if (node->parent->nodeid == parent && strcmp(node->name, name) == 0) + return node; + + return NULL; +} + +static struct node *find_node(struct fuse *f, fuse_ino_t parent, + const char *name) +{ + struct node *node; + + pthread_mutex_lock(&f->lock); + node = lookup_node(f, parent, name); + if (node == NULL) { + node = (struct node *) calloc(1, sizeof(struct node)); + if (node == NULL) + goto out_err; + + node->refctr = 1; + node->nodeid = next_id(f); + node->open_count = 0; + node->is_hidden = 0; + node->generation = f->generation; + if (hash_name(f, node, parent, name) == -1) { + free(node); + node = NULL; + goto out_err; + } + hash_id(f, node); + } + node->nlookup ++; + out_err: + pthread_mutex_unlock(&f->lock); + return node; +} + +static char *add_name(char **buf, unsigned *bufsize, char *s, const char *name) +{ + size_t len = strlen(name); + + if (s - len <= *buf) { + unsigned pathlen = *bufsize - (s - *buf); + unsigned newbufsize = *bufsize; + char *newbuf; + + while (newbufsize < pathlen + len + 1) { + if (newbufsize >= 0x80000000) + newbufsize = 0xffffffff; + else + newbufsize *= 2; + } + + newbuf = realloc(*buf, newbufsize); + if (newbuf == NULL) + return NULL; + + *buf = newbuf; + s = newbuf + newbufsize - pathlen; + memmove(s, newbuf + *bufsize - pathlen, pathlen); + *bufsize = newbufsize; + } + s -= len; + strncpy(s, name, len); + s--; + *s = '/'; + + return s; +} + +static char *get_path_name(struct fuse *f, fuse_ino_t nodeid, const char *name) +{ + unsigned bufsize = 256; + char *buf; + char *s; + struct node *node; + + buf = malloc(bufsize); + if (buf == NULL) + return NULL; + + s = buf + bufsize - 1; + *s = '\0'; + + if (name != NULL) { + s = add_name(&buf, &bufsize, s, name); + if (s == NULL) + goto out_free; + } + + pthread_mutex_lock(&f->lock); + for (node = get_node(f, nodeid); node && node->nodeid != FUSE_ROOT_ID; + node = node->parent) { + if (node->name == NULL) { + s = NULL; + break; + } + + s = add_name(&buf, &bufsize, s, node->name); + if (s == NULL) + break; + } + pthread_mutex_unlock(&f->lock); + + if (node == NULL || s == NULL) + goto out_free; + + if (s[0]) + memmove(buf, s, bufsize - (s - buf)); + else + strcpy(buf, "/"); + return buf; + +out_free: + free(buf); + return NULL; +} + +static char *get_path(struct fuse *f, fuse_ino_t nodeid) +{ + return get_path_name(f, nodeid, NULL); +} + +static void forget_node(struct fuse *f, fuse_ino_t nodeid, uint64_t nlookup) +{ + struct node *node; + if (nodeid == FUSE_ROOT_ID) + return; + pthread_mutex_lock(&f->lock); + node = get_node(f, nodeid); + assert(node->nlookup >= nlookup); + node->nlookup -= nlookup; + if (!node->nlookup) { + unhash_name(f, node); + unref_node(f, node); + } + pthread_mutex_unlock(&f->lock); +} + +static void remove_node(struct fuse *f, fuse_ino_t dir, const char *name) +{ + struct node *node; + + pthread_mutex_lock(&f->lock); + node = lookup_node(f, dir, name); + if (node != NULL) + unhash_name(f, node); + pthread_mutex_unlock(&f->lock); +} + +static int rename_node(struct fuse *f, fuse_ino_t olddir, const char *oldname, + fuse_ino_t newdir, const char *newname, int hide) +{ + struct node *node; + struct node *newnode; + int err = 0; + + pthread_mutex_lock(&f->lock); + node = lookup_node(f, olddir, oldname); + newnode = lookup_node(f, newdir, newname); + if (node == NULL) + goto out; + + if (newnode != NULL) { + if (hide) { + fprintf(stderr, "fuse: hidden file got created during hiding\n"); + err = -EBUSY; + goto out; + } + unhash_name(f, newnode); + } + + unhash_name(f, node); + if (hash_name(f, node, newdir, newname) == -1) { + err = -ENOMEM; + goto out; + } + + if (hide) + node->is_hidden = 1; + + out: + pthread_mutex_unlock(&f->lock); + return err; +} + +static void set_stat(struct fuse *f, fuse_ino_t nodeid, struct stat *stbuf) +{ + if (!f->conf.use_ino) + stbuf->st_ino = nodeid; + if (f->conf.set_mode) + stbuf->st_mode = (stbuf->st_mode & S_IFMT) | (0777 & ~f->conf.umask); + if (f->conf.set_uid) + stbuf->st_uid = f->conf.uid; + if (f->conf.set_gid) + stbuf->st_gid = f->conf.gid; +} + +static struct fuse *req_fuse(fuse_req_t req) +{ + return (struct fuse *) fuse_req_userdata(req); +} + +static void fuse_intr_sighandler(int sig) +{ + (void) sig; + /* Nothing to do */ +} + +struct fuse_intr_data { + pthread_t id; + pthread_cond_t cond; + int finished; +}; + +static void fuse_interrupt(fuse_req_t req, void *d_) +{ + struct fuse_intr_data *d = d_; + struct fuse *f = req_fuse(req); + + if (d->id == pthread_self()) + return; + + pthread_mutex_lock(&f->lock); + while (!d->finished) { + struct timeval now; + struct timespec timeout; + + pthread_kill(d->id, f->conf.intr_signal); + gettimeofday(&now, NULL); + timeout.tv_sec = now.tv_sec + 1; + timeout.tv_nsec = now.tv_usec * 1000; + pthread_cond_timedwait(&d->cond, &f->lock, &timeout); + } + pthread_mutex_unlock(&f->lock); +} + +static void fuse_do_finish_interrupt(struct fuse *f, fuse_req_t req, + struct fuse_intr_data *d) +{ + pthread_mutex_lock(&f->lock); + d->finished = 1; + pthread_cond_broadcast(&d->cond); + pthread_mutex_unlock(&f->lock); + fuse_req_interrupt_func(req, NULL, NULL); + pthread_cond_destroy(&d->cond); +} + +static void fuse_do_prepare_interrupt(fuse_req_t req, struct fuse_intr_data *d) +{ + d->id = pthread_self(); + pthread_cond_init(&d->cond, NULL); + d->finished = 0; + fuse_req_interrupt_func(req, fuse_interrupt, d); +} + +static void fuse_finish_interrupt(struct fuse *f, fuse_req_t req, + struct fuse_intr_data *d) +{ + if (f->conf.intr) + fuse_do_finish_interrupt(f, req, d); +} + +static void fuse_prepare_interrupt(struct fuse *f, fuse_req_t req, + struct fuse_intr_data *d) +{ + if (f->conf.intr) + fuse_do_prepare_interrupt(req, d); +} + +int fuse_fs_getattr(struct fuse_fs *fs, const char *path, struct stat *buf) +{ + fuse_get_context()->private_data = fs->user_data; + if (fs->op.getattr) + return fs->op.getattr(path, buf); + else + return -ENOSYS; +} + +int fuse_fs_fgetattr(struct fuse_fs *fs, const char *path, struct stat *buf, + struct fuse_file_info *fi) +{ + fuse_get_context()->private_data = fs->user_data; + if (fs->op.fgetattr) + return fs->op.fgetattr(path, buf, fi); + else if (fs->op.getattr) + return fs->op.getattr(path, buf); + else + return -ENOSYS; +} + +int fuse_fs_rename(struct fuse_fs *fs, const char *oldpath, + const char *newpath) +{ + fuse_get_context()->private_data = fs->user_data; + if (fs->op.rename) + return fs->op.rename(oldpath, newpath); + else + return -ENOSYS; +} + +int fuse_fs_unlink(struct fuse_fs *fs, const char *path) +{ + fuse_get_context()->private_data = fs->user_data; + if (fs->op.unlink) + return fs->op.unlink(path); + else + return -ENOSYS; +} + +int fuse_fs_rmdir(struct fuse_fs *fs, const char *path) +{ + fuse_get_context()->private_data = fs->user_data; + if (fs->op.rmdir) + return fs->op.rmdir(path); + else + return -ENOSYS; +} + +int fuse_fs_symlink(struct fuse_fs *fs, const char *linkname, const char *path) +{ + fuse_get_context()->private_data = fs->user_data; + if (fs->op.symlink) + return fs->op.symlink(linkname, path); + else + return -ENOSYS; +} + +int fuse_fs_link(struct fuse_fs *fs, const char *oldpath, const char *newpath) +{ + fuse_get_context()->private_data = fs->user_data; + if (fs->op.link) + return fs->op.link(oldpath, newpath); + else + return -ENOSYS; +} + +int fuse_fs_release(struct fuse_fs *fs, const char *path, + struct fuse_file_info *fi) +{ + fuse_get_context()->private_data = fs->user_data; + if (fs->op.release) + return fs->op.release(path, fi); + else + return 0; +} + +int fuse_fs_opendir(struct fuse_fs *fs, const char *path, + struct fuse_file_info *fi) +{ + fuse_get_context()->private_data = fs->user_data; + if (fs->op.opendir) + return fs->op.opendir(path, fi); + else + return 0; +} + +int fuse_fs_open(struct fuse_fs *fs, const char *path, + struct fuse_file_info *fi) +{ + fuse_get_context()->private_data = fs->user_data; + if (fs->op.open) + return fs->op.open(path, fi); + else + return 0; +} + +int fuse_fs_read(struct fuse_fs *fs, const char *path, char *buf, size_t size, + off_t off, struct fuse_file_info *fi) +{ + fuse_get_context()->private_data = fs->user_data; + if (fs->op.read) + return fs->op.read(path, buf, size, off, fi); + else + return -ENOSYS; +} + +int fuse_fs_write(struct fuse_fs *fs, const char *path, const char *buf, + size_t size, off_t off, struct fuse_file_info *fi) +{ + fuse_get_context()->private_data = fs->user_data; + if (fs->op.write) + return fs->op.write(path, buf, size, off, fi); + else + return -ENOSYS; +} + +int fuse_fs_fsync(struct fuse_fs *fs, const char *path, int datasync, + struct fuse_file_info *fi) +{ + fuse_get_context()->private_data = fs->user_data; + if (fs->op.fsync) + return fs->op.fsync(path, datasync, fi); + else + return -ENOSYS; +} + +int fuse_fs_fsyncdir(struct fuse_fs *fs, const char *path, int datasync, + struct fuse_file_info *fi) +{ + fuse_get_context()->private_data = fs->user_data; + if (fs->op.fsyncdir) + return fs->op.fsyncdir(path, datasync, fi); + else + return -ENOSYS; +} + +int fuse_fs_flush(struct fuse_fs *fs, const char *path, + struct fuse_file_info *fi) +{ + fuse_get_context()->private_data = fs->user_data; + if (fs->op.flush) + return fs->op.flush(path, fi); + else + return -ENOSYS; +} + +#if HAVE_SYS_STATVFS_H +int fuse_fs_statfs(struct fuse_fs *fs, const char *path, struct statvfs *buf) +{ + fuse_get_context()->private_data = fs->user_data; + if (fs->op.statfs) + return fs->op.statfs(path, buf); + else { + buf->f_namemax = 255; + buf->f_bsize = 512; + return 0; + } +} +#endif + +int fuse_fs_releasedir(struct fuse_fs *fs, const char *path, + struct fuse_file_info *fi) +{ + fuse_get_context()->private_data = fs->user_data; + if (fs->op.releasedir) + return fs->op.releasedir(path, fi); + else + return 0; +} + +int fuse_fs_readdir(struct fuse_fs *fs, const char *path, void *buf, + fuse_fill_dir_t filler, off_t off, + struct fuse_file_info *fi) +{ + fuse_get_context()->private_data = fs->user_data; + if (fs->op.readdir) + return fs->op.readdir(path, buf, filler, off, fi); + else + return -ENOSYS; +} + +int fuse_fs_create(struct fuse_fs *fs, const char *path, mode_t mode, + struct fuse_file_info *fi) +{ + fuse_get_context()->private_data = fs->user_data; + if (fs->op.create) + return fs->op.create(path, mode, fi); + else + return -ENOSYS; +} + +int fuse_fs_lock(struct fuse_fs *fs, const char *path, + struct fuse_file_info *fi, int cmd, struct flock *lock) +{ + fuse_get_context()->private_data = fs->user_data; + if (fs->op.lock) + return fs->op.lock(path, fi, cmd, lock); + else + return -ENOSYS; +} + +int fuse_fs_chown(struct fuse_fs *fs, const char *path, uid_t uid, gid_t gid) +{ + fuse_get_context()->private_data = fs->user_data; + if (fs->op.chown) + return fs->op.chown(path, uid, gid); + else + return -ENOSYS; +} + +int fuse_fs_truncate(struct fuse_fs *fs, const char *path, off_t size) +{ + fuse_get_context()->private_data = fs->user_data; + if (fs->op.truncate) + return fs->op.truncate(path, size); + else + return -ENOSYS; +} + +int fuse_fs_ftruncate(struct fuse_fs *fs, const char *path, off_t size, + struct fuse_file_info *fi) +{ + fuse_get_context()->private_data = fs->user_data; + if (fs->op.ftruncate) + return fs->op.ftruncate(path, size, fi); + else if (fs->op.truncate) + return fs->op.truncate(path, size); + else + return -ENOSYS; +} + +int fuse_fs_utimens(struct fuse_fs *fs, const char *path, + const struct timespec tv[2]) +{ + fuse_get_context()->private_data = fs->user_data; + if (fs->op.utimens) + return fs->op.utimens(path, tv); + else if(fs->op.utime) { + struct utimbuf buf; + buf.actime = tv[0].tv_sec; + buf.modtime = tv[1].tv_sec; + return fs->op.utime(path, &buf); + } else + return -ENOSYS; +} + +int fuse_fs_access(struct fuse_fs *fs, const char *path, int mask) +{ + fuse_get_context()->private_data = fs->user_data; + if (fs->op.access) + return fs->op.access(path, mask); + else + return -ENOSYS; +} + +int fuse_fs_readlink(struct fuse_fs *fs, const char *path, char *buf, + size_t len) +{ + fuse_get_context()->private_data = fs->user_data; + if (fs->op.readlink) + return fs->op.readlink(path, buf, len); + else + return -ENOSYS; +} + +int fuse_fs_mknod(struct fuse_fs *fs, const char *path, mode_t mode, + dev_t rdev) +{ + fuse_get_context()->private_data = fs->user_data; + if (fs->op.mknod) + return fs->op.mknod(path, mode, rdev); + else + return -ENOSYS; +} + +int fuse_fs_mkdir(struct fuse_fs *fs, const char *path, mode_t mode) +{ + fuse_get_context()->private_data = fs->user_data; + if (fs->op.mkdir) + return fs->op.mkdir(path, mode); + else + return -ENOSYS; +} + +int fuse_fs_setxattr(struct fuse_fs *fs, const char *path, const char *name, + const char *value, size_t size, int flags) +{ + fuse_get_context()->private_data = fs->user_data; + if (fs->op.setxattr) + return fs->op.setxattr(path, name, value, size, flags); + else + return -ENOSYS; +} + +int fuse_fs_getxattr(struct fuse_fs *fs, const char *path, const char *name, + char *value, size_t size) +{ + fuse_get_context()->private_data = fs->user_data; + if (fs->op.getxattr) + return fs->op.getxattr(path, name, value, size); + else + return -ENOSYS; +} + +int fuse_fs_listxattr(struct fuse_fs *fs, const char *path, char *list, + size_t size) +{ + fuse_get_context()->private_data = fs->user_data; + if (fs->op.listxattr) + return fs->op.listxattr(path, list, size); + else + return -ENOSYS; +} + +int fuse_fs_bmap(struct fuse_fs *fs, const char *path, size_t blocksize, + uint64_t *idx) +{ + fuse_get_context()->private_data = fs->user_data; + if (fs->op.bmap) + return fs->op.bmap(path, blocksize, idx); + else + return -ENOSYS; +} + +int fuse_fs_removexattr(struct fuse_fs *fs, const char *path, const char *name) +{ + fuse_get_context()->private_data = fs->user_data; + if (fs->op.removexattr) + return fs->op.removexattr(path, name); + else + return -ENOSYS; +} + +static int is_open(struct fuse *f, fuse_ino_t dir, const char *name) +{ + struct node *node; + int isopen = 0; + pthread_mutex_lock(&f->lock); + node = lookup_node(f, dir, name); + if (node && node->open_count > 0) + isopen = 1; + pthread_mutex_unlock(&f->lock); + return isopen; +} + +static char *hidden_name(struct fuse *f, fuse_ino_t dir, const char *oldname, + char *newname, size_t bufsize) +{ + struct stat buf; + struct node *node; + struct node *newnode; + char *newpath; + int res; + int failctr = 10; + + do { + pthread_mutex_lock(&f->lock); + node = lookup_node(f, dir, oldname); + if (node == NULL) { + pthread_mutex_unlock(&f->lock); + return NULL; + } + do { + f->hidectr ++; + snprintf(newname, bufsize, ".fuse_hidden%08x%08x", + (unsigned int) node->nodeid, f->hidectr); + newnode = lookup_node(f, dir, newname); + } while(newnode); + pthread_mutex_unlock(&f->lock); + + newpath = get_path_name(f, dir, newname); + if (!newpath) + break; + + res = fuse_fs_getattr(f->fs, newpath, &buf); + if (res == -ENOENT) + break; + free(newpath); + newpath = NULL; + } while(res == 0 && --failctr); + + return newpath; +} + +static int hide_node(struct fuse *f, const char *oldpath, + fuse_ino_t dir, const char *oldname) +{ + char newname[64]; + char *newpath; + int err = -EBUSY; + + newpath = hidden_name(f, dir, oldname, newname, sizeof(newname)); + if (newpath) { + err = fuse_fs_rename(f->fs, oldpath, newpath); + if (!err) + err = rename_node(f, dir, oldname, dir, newname, 1); + free(newpath); + } + return err; +} + +static int lookup_path(struct fuse *f, fuse_ino_t nodeid, + const char *name, const char *path, + struct fuse_entry_param *e, struct fuse_file_info *fi) +{ + int res; + + memset(e, 0, sizeof(struct fuse_entry_param)); + if (fi) + res = fuse_fs_fgetattr(f->fs, path, &e->attr, fi); + else + res = fuse_fs_getattr(f->fs, path, &e->attr); + if (res == 0) { + struct node *node; + + node = find_node(f, nodeid, name); + if (node == NULL) + res = -ENOMEM; + else { + e->ino = node->nodeid; + e->generation = node->generation; + e->entry_timeout = f->conf.entry_timeout; + e->attr_timeout = f->conf.attr_timeout; + set_stat(f, e->ino, &e->attr); + if (f->conf.debug) + fprintf(stderr, " NODEID: %lu\n", (unsigned long) e->ino); + } + } + return res; +} + +static struct fuse_context_i *fuse_get_context_internal(void) +{ + struct fuse_context_i *c; + + c = (struct fuse_context_i *) pthread_getspecific(fuse_context_key); + if (c == NULL) { + c = (struct fuse_context_i *) malloc(sizeof(struct fuse_context_i)); + if (c == NULL) { + /* This is hard to deal with properly, so just abort. If + memory is so low that the context cannot be allocated, + there's not much hope for the filesystem anyway */ + fprintf(stderr, "fuse: failed to allocate thread specific data\n"); + abort(); + } + pthread_setspecific(fuse_context_key, c); + } + return c; +} + +static void fuse_freecontext(void *data) +{ + free(data); +} + +static int fuse_create_context_key(void) +{ + int err = 0; + pthread_mutex_lock(&fuse_context_lock); + if (!fuse_context_ref) { + err = pthread_key_create(&fuse_context_key, fuse_freecontext); + if (err) { + fprintf(stderr, "fuse: failed to create thread specific key: %s\n", + strerror(err)); + pthread_mutex_unlock(&fuse_context_lock); + return -1; + } + } + fuse_context_ref++; + pthread_mutex_unlock(&fuse_context_lock); + return 0; +} + +static void fuse_delete_context_key(void) +{ + pthread_mutex_lock(&fuse_context_lock); + fuse_context_ref--; + if (!fuse_context_ref) { + free(pthread_getspecific(fuse_context_key)); + pthread_key_delete(fuse_context_key); + } + pthread_mutex_unlock(&fuse_context_lock); +} + +static struct fuse *req_fuse_prepare(fuse_req_t req) +{ + struct fuse_context_i *c = fuse_get_context_internal(); + const struct fuse_ctx *ctx = fuse_req_ctx(req); + c->req = req; + c->ctx.fuse = req_fuse(req); + c->ctx.uid = ctx->uid; + c->ctx.gid = ctx->gid; + c->ctx.pid = ctx->pid; +#ifdef POSIXACLS + c->ctx.umask = ctx->umask; +#endif + return c->ctx.fuse; +} + +static void reply_err(fuse_req_t req, int err) +{ + /* fuse_reply_err() uses non-negated errno values */ + fuse_reply_err(req, -err); +} + +static void reply_entry(fuse_req_t req, const struct fuse_entry_param *e, + int err) +{ + if (!err) { + struct fuse *f = req_fuse(req); + if (fuse_reply_entry(req, e) == -ENOENT) + forget_node(f, e->ino, 1); + } else + reply_err(req, err); +} + +void fuse_fs_init(struct fuse_fs *fs, struct fuse_conn_info *conn) +{ + fuse_get_context()->private_data = fs->user_data; + if (fs->op.init) + fs->user_data = fs->op.init(conn); +} + +static void fuse_lib_init(void *data, struct fuse_conn_info *conn) +{ + struct fuse *f = (struct fuse *) data; + struct fuse_context_i *c = fuse_get_context_internal(); + + memset(c, 0, sizeof(*c)); + c->ctx.fuse = f; + fuse_fs_init(f->fs, conn); +} + +void fuse_fs_destroy(struct fuse_fs *fs) +{ + fuse_get_context()->private_data = fs->user_data; + if (fs->op.destroy) + fs->op.destroy(fs->user_data); + free(fs); +} + +static void fuse_lib_destroy(void *data) +{ + struct fuse *f = (struct fuse *) data; + struct fuse_context_i *c = fuse_get_context_internal(); + + memset(c, 0, sizeof(*c)); + c->ctx.fuse = f; + fuse_fs_destroy(f->fs); + f->fs = NULL; +} + +static void fuse_lib_lookup(fuse_req_t req, fuse_ino_t parent, + const char *name) +{ + struct fuse *f = req_fuse_prepare(req); + struct fuse_entry_param e; + char *path; + int err; + + err = -ENOENT; + pthread_rwlock_rdlock(&f->tree_lock); + path = get_path_name(f, parent, name); + if (path != NULL) { + struct fuse_intr_data d; + if (f->conf.debug) + fprintf(stderr, "LOOKUP %s\n", path); + fuse_prepare_interrupt(f, req, &d); + err = lookup_path(f, parent, name, path, &e, NULL); + if (err == -ENOENT && f->conf.negative_timeout != 0.0) { + e.ino = 0; + e.entry_timeout = f->conf.negative_timeout; + err = 0; + } + fuse_finish_interrupt(f, req, &d); + free(path); + } + pthread_rwlock_unlock(&f->tree_lock); + reply_entry(req, &e, err); +} + +static void fuse_lib_forget(fuse_req_t req, fuse_ino_t ino, + unsigned long nlookup) +{ + struct fuse *f = req_fuse(req); + if (f->conf.debug) + fprintf(stderr, "FORGET %llu/%lu\n", (unsigned long long)ino, nlookup); + forget_node(f, ino, nlookup); + fuse_reply_none(req); +} + +static void fuse_lib_getattr(fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *fi) +{ + struct fuse *f = req_fuse_prepare(req); + struct stat buf; + char *path; + int err; + + (void) fi; + memset(&buf, 0, sizeof(buf)); + + err = -ENOENT; + pthread_rwlock_rdlock(&f->tree_lock); + path = get_path(f, ino); + if (path != NULL) { + struct fuse_intr_data d; + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_getattr(f->fs, path, &buf); + fuse_finish_interrupt(f, req, &d); + free(path); + } + pthread_rwlock_unlock(&f->tree_lock); + if (!err) { + set_stat(f, ino, &buf); + fuse_reply_attr(req, &buf, f->conf.attr_timeout); + } else + reply_err(req, err); +} + +int fuse_fs_chmod(struct fuse_fs *fs, const char *path, mode_t mode) +{ + fuse_get_context()->private_data = fs->user_data; + if (fs->op.chmod) + return fs->op.chmod(path, mode); + else + return -ENOSYS; +} + +static void fuse_lib_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr, + int valid, struct fuse_file_info *fi) +{ + struct fuse *f = req_fuse_prepare(req); + struct stat buf; + char *path; + int err; + + err = -ENOENT; + pthread_rwlock_rdlock(&f->tree_lock); + path = get_path(f, ino); + if (path != NULL) { + struct fuse_intr_data d; + fuse_prepare_interrupt(f, req, &d); + err = 0; + if (!err && (valid & FUSE_SET_ATTR_MODE)) + err = fuse_fs_chmod(f->fs, path, attr->st_mode); + if (!err && (valid & (FUSE_SET_ATTR_UID | FUSE_SET_ATTR_GID))) { + uid_t uid = + (valid & FUSE_SET_ATTR_UID) ? attr->st_uid : (uid_t) -1; + gid_t gid = + (valid & FUSE_SET_ATTR_GID) ? attr->st_gid : (gid_t) -1; + err = fuse_fs_chown(f->fs, path, uid, gid); + } + if (!err && (valid & FUSE_SET_ATTR_SIZE)) { + if (fi) + err = fuse_fs_ftruncate(f->fs, path, attr->st_size, fi); + else + err = fuse_fs_truncate(f->fs, path, attr->st_size); + } +#ifdef HAVE_UTIMENSAT + if (!err && f->utime_omit_ok && + (valid & (FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME))) { + struct timespec tv[2]; + + tv[0].tv_sec = 0; + tv[1].tv_sec = 0; + tv[0].tv_nsec = UTIME_OMIT; + tv[1].tv_nsec = UTIME_OMIT; + + if (valid & FUSE_SET_ATTR_ATIME_NOW) + tv[0].tv_nsec = UTIME_NOW; + else if (valid & FUSE_SET_ATTR_ATIME) + tv[0] = attr->st_atim; + + if (valid & FUSE_SET_ATTR_MTIME_NOW) + tv[1].tv_nsec = UTIME_NOW; + else if (valid & FUSE_SET_ATTR_MTIME) + tv[1] = attr->st_mtim; + + err = fuse_fs_utimens(f->fs, path, tv); + } else +#endif + if (!err && (valid & (FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME)) == + (FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME)) { + struct timespec tv[2]; + tv[0].tv_sec = attr->st_atime; + tv[0].tv_nsec = ST_ATIM_NSEC(attr); + tv[1].tv_sec = attr->st_mtime; + tv[1].tv_nsec = ST_MTIM_NSEC(attr); + err = fuse_fs_utimens(f->fs, path, tv); + } + if (!err) + err = fuse_fs_getattr(f->fs, path, &buf); + fuse_finish_interrupt(f, req, &d); + free(path); + } + pthread_rwlock_unlock(&f->tree_lock); + if (!err) { + set_stat(f, ino, &buf); + fuse_reply_attr(req, &buf, f->conf.attr_timeout); + } else + reply_err(req, err); +} + +static void fuse_lib_access(fuse_req_t req, fuse_ino_t ino, int mask) +{ + struct fuse *f = req_fuse_prepare(req); + char *path; + int err; + + err = -ENOENT; + pthread_rwlock_rdlock(&f->tree_lock); + path = get_path(f, ino); + if (path != NULL) { + struct fuse_intr_data d; + if (f->conf.debug) + fprintf(stderr, "ACCESS %s 0%o\n", path, mask); + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_access(f->fs, path, mask); + fuse_finish_interrupt(f, req, &d); + free(path); + } + pthread_rwlock_unlock(&f->tree_lock); + reply_err(req, err); +} + +static void fuse_lib_readlink(fuse_req_t req, fuse_ino_t ino) +{ + struct fuse *f = req_fuse_prepare(req); + char linkname[PATH_MAX + 1]; + char *path; + int err; + + err = -ENOENT; + pthread_rwlock_rdlock(&f->tree_lock); + path = get_path(f, ino); + if (path != NULL) { + struct fuse_intr_data d; + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_readlink(f->fs, path, linkname, sizeof(linkname)); + fuse_finish_interrupt(f, req, &d); + free(path); + } + pthread_rwlock_unlock(&f->tree_lock); + if (!err) { + linkname[PATH_MAX] = '\0'; + fuse_reply_readlink(req, linkname); + } else + reply_err(req, err); +} + +static void fuse_lib_mknod(fuse_req_t req, fuse_ino_t parent, const char *name, + mode_t mode, dev_t rdev) +{ + struct fuse *f = req_fuse_prepare(req); + struct fuse_entry_param e; + char *path; + int err; + + err = -ENOENT; + pthread_rwlock_rdlock(&f->tree_lock); + path = get_path_name(f, parent, name); + if (path) { + struct fuse_intr_data d; + if (f->conf.debug) + fprintf(stderr, "MKNOD %s\n", path); + fuse_prepare_interrupt(f, req, &d); + err = -ENOSYS; + if (S_ISREG(mode)) { + struct fuse_file_info fi; + + memset(&fi, 0, sizeof(fi)); + fi.flags = O_CREAT | O_EXCL | O_WRONLY; + err = fuse_fs_create(f->fs, path, mode, &fi); + if (!err) { + err = lookup_path(f, parent, name, path, &e, &fi); + fuse_fs_release(f->fs, path, &fi); + } + } + if (err == -ENOSYS) { + err = fuse_fs_mknod(f->fs, path, mode, rdev); + if (!err) + err = lookup_path(f, parent, name, path, &e, NULL); + } + fuse_finish_interrupt(f, req, &d); + free(path); + } + pthread_rwlock_unlock(&f->tree_lock); + reply_entry(req, &e, err); +} + +static void fuse_lib_mkdir(fuse_req_t req, fuse_ino_t parent, const char *name, + mode_t mode) +{ + struct fuse *f = req_fuse_prepare(req); + struct fuse_entry_param e; + char *path; + int err; + + err = -ENOENT; + pthread_rwlock_rdlock(&f->tree_lock); + path = get_path_name(f, parent, name); + if (path != NULL) { + struct fuse_intr_data d; + if (f->conf.debug) + fprintf(stderr, "MKDIR %s\n", path); + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_mkdir(f->fs, path, mode); + if (!err) + err = lookup_path(f, parent, name, path, &e, NULL); + fuse_finish_interrupt(f, req, &d); + free(path); + } + pthread_rwlock_unlock(&f->tree_lock); + reply_entry(req, &e, err); +} + +static void fuse_lib_unlink(fuse_req_t req, fuse_ino_t parent, + const char *name) +{ + struct fuse *f = req_fuse_prepare(req); + char *path; + int err; + + err = -ENOENT; + pthread_rwlock_wrlock(&f->tree_lock); + path = get_path_name(f, parent, name); + if (path != NULL) { + struct fuse_intr_data d; + if (f->conf.debug) + fprintf(stderr, "UNLINK %s\n", path); + fuse_prepare_interrupt(f, req, &d); + if (!f->conf.hard_remove && is_open(f, parent, name)) + err = hide_node(f, path, parent, name); + else { + err = fuse_fs_unlink(f->fs, path); + if (!err) + remove_node(f, parent, name); + } + fuse_finish_interrupt(f, req, &d); + free(path); + } + pthread_rwlock_unlock(&f->tree_lock); + reply_err(req, err); +} + +static void fuse_lib_rmdir(fuse_req_t req, fuse_ino_t parent, const char *name) +{ + struct fuse *f = req_fuse_prepare(req); + char *path; + int err; + + err = -ENOENT; + pthread_rwlock_wrlock(&f->tree_lock); + path = get_path_name(f, parent, name); + if (path != NULL) { + struct fuse_intr_data d; + if (f->conf.debug) + fprintf(stderr, "RMDIR %s\n", path); + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_rmdir(f->fs, path); + fuse_finish_interrupt(f, req, &d); + if (!err) + remove_node(f, parent, name); + free(path); + } + pthread_rwlock_unlock(&f->tree_lock); + reply_err(req, err); +} + +static void fuse_lib_symlink(fuse_req_t req, const char *linkname, + fuse_ino_t parent, const char *name) +{ + struct fuse *f = req_fuse_prepare(req); + struct fuse_entry_param e; + char *path; + int err; + + err = -ENOENT; + pthread_rwlock_rdlock(&f->tree_lock); + path = get_path_name(f, parent, name); + if (path != NULL) { + struct fuse_intr_data d; + if (f->conf.debug) + fprintf(stderr, "SYMLINK %s\n", path); + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_symlink(f->fs, linkname, path); + if (!err) + err = lookup_path(f, parent, name, path, &e, NULL); + fuse_finish_interrupt(f, req, &d); + free(path); + } + pthread_rwlock_unlock(&f->tree_lock); + reply_entry(req, &e, err); +} + +static void fuse_lib_rename(fuse_req_t req, fuse_ino_t olddir, + const char *oldname, fuse_ino_t newdir, + const char *newname) +{ + struct fuse *f = req_fuse_prepare(req); + char *oldpath; + char *newpath; + int err; + + err = -ENOENT; + pthread_rwlock_wrlock(&f->tree_lock); + oldpath = get_path_name(f, olddir, oldname); + if (oldpath != NULL) { + newpath = get_path_name(f, newdir, newname); + if (newpath != NULL) { + struct fuse_intr_data d; + if (f->conf.debug) + fprintf(stderr, "RENAME %s -> %s\n", oldpath, newpath); + err = 0; + fuse_prepare_interrupt(f, req, &d); + if (!f->conf.hard_remove && is_open(f, newdir, newname)) + err = hide_node(f, newpath, newdir, newname); + if (!err) { + err = fuse_fs_rename(f->fs, oldpath, newpath); + if (!err) + err = rename_node(f, olddir, oldname, newdir, newname, 0); + } + fuse_finish_interrupt(f, req, &d); + free(newpath); + } + free(oldpath); + } + pthread_rwlock_unlock(&f->tree_lock); + reply_err(req, err); +} + +static void fuse_lib_link(fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent, + const char *newname) +{ + struct fuse *f = req_fuse_prepare(req); + struct fuse_entry_param e; + char *oldpath; + char *newpath; + int err; + + err = -ENOENT; + pthread_rwlock_rdlock(&f->tree_lock); + oldpath = get_path(f, ino); + if (oldpath != NULL) { + newpath = get_path_name(f, newparent, newname); + if (newpath != NULL) { + struct fuse_intr_data d; + if (f->conf.debug) + fprintf(stderr, "LINK %s\n", newpath); + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_link(f->fs, oldpath, newpath); + if (!err) + err = lookup_path(f, newparent, newname, newpath, &e, NULL); + fuse_finish_interrupt(f, req, &d); + free(newpath); + } + free(oldpath); + } + pthread_rwlock_unlock(&f->tree_lock); + reply_entry(req, &e, err); +} + +static void fuse_do_release(struct fuse *f, fuse_ino_t ino, const char *path, + struct fuse_file_info *fi) +{ + struct node *node; + int unlink_hidden = 0; + + fuse_fs_release(f->fs, path ? path : "-", fi); + + pthread_mutex_lock(&f->lock); + node = get_node(f, ino); + assert(node->open_count > 0); + --node->open_count; + if (node->is_hidden && !node->open_count) { + unlink_hidden = 1; + node->is_hidden = 0; + } + pthread_mutex_unlock(&f->lock); + + if(unlink_hidden && path) + fuse_fs_unlink(f->fs, path); +} + +static void fuse_lib_create(fuse_req_t req, fuse_ino_t parent, + const char *name, mode_t mode, + struct fuse_file_info *fi) +{ + struct fuse *f = req_fuse_prepare(req); + struct fuse_intr_data d; + struct fuse_entry_param e; + char *path; + int err; + + err = -ENOENT; + pthread_rwlock_rdlock(&f->tree_lock); + path = get_path_name(f, parent, name); + if (path) { + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_create(f->fs, path, mode, fi); + if (!err) { + err = lookup_path(f, parent, name, path, &e, fi); + if (err) + fuse_fs_release(f->fs, path, fi); + else if (!S_ISREG(e.attr.st_mode)) { + err = -EIO; + fuse_fs_release(f->fs, path, fi); + forget_node(f, e.ino, 1); + } else { + if (f->conf.direct_io) + fi->direct_io = 1; + if (f->conf.kernel_cache) + fi->keep_cache = 1; + + } + } + fuse_finish_interrupt(f, req, &d); + } + if (!err) { + pthread_mutex_lock(&f->lock); + get_node(f, e.ino)->open_count++; + pthread_mutex_unlock(&f->lock); + if (fuse_reply_create(req, &e, fi) == -ENOENT) { + /* The open syscall was interrupted, so it must be cancelled */ + fuse_prepare_interrupt(f, req, &d); + fuse_do_release(f, e.ino, path, fi); + fuse_finish_interrupt(f, req, &d); + forget_node(f, e.ino, 1); + } else if (f->conf.debug) { + fprintf(stderr, " CREATE[%llu] flags: 0x%x %s\n", + (unsigned long long) fi->fh, fi->flags, path); + } + } else + reply_err(req, err); + + if (path) + free(path); + + pthread_rwlock_unlock(&f->tree_lock); +} + +static void fuse_lib_open(fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *fi) +{ + struct fuse *f = req_fuse_prepare(req); + struct fuse_intr_data d; + char *path = NULL; + int err = 0; + + err = -ENOENT; + pthread_rwlock_rdlock(&f->tree_lock); + path = get_path(f, ino); + if (path) { + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_open(f->fs, path, fi); + if (!err) { + if (f->conf.direct_io) + fi->direct_io = 1; + if (f->conf.kernel_cache) + fi->keep_cache = 1; + } + fuse_finish_interrupt(f, req, &d); + } + if (!err) { + pthread_mutex_lock(&f->lock); + get_node(f, ino)->open_count++; + pthread_mutex_unlock(&f->lock); + if (fuse_reply_open(req, fi) == -ENOENT) { + /* The open syscall was interrupted, so it must be cancelled */ + fuse_prepare_interrupt(f, req, &d); + fuse_do_release(f, ino, path, fi); + fuse_finish_interrupt(f, req, &d); + } else if (f->conf.debug) { + fprintf(stderr, "OPEN[%llu] flags: 0x%x %s\n", + (unsigned long long) fi->fh, fi->flags, path); + } + } else + reply_err(req, err); + + if (path) + free(path); + pthread_rwlock_unlock(&f->tree_lock); +} + +static void fuse_lib_read(fuse_req_t req, fuse_ino_t ino, size_t size, + off_t off, struct fuse_file_info *fi) +{ + struct fuse *f = req_fuse_prepare(req); + char *path; + char *buf; + int res; + + buf = (char *) malloc(size); + if (buf == NULL) { + reply_err(req, -ENOMEM); + return; + } + + res = -ENOENT; + pthread_rwlock_rdlock(&f->tree_lock); + path = get_path(f, ino); + if (path != NULL) { + struct fuse_intr_data d; + if (f->conf.debug) + fprintf(stderr, "READ[%llu] %lu bytes from %llu\n", + (unsigned long long) fi->fh, (unsigned long) size, + (unsigned long long) off); + + fuse_prepare_interrupt(f, req, &d); + res = fuse_fs_read(f->fs, path, buf, size, off, fi); + fuse_finish_interrupt(f, req, &d); + free(path); + } + pthread_rwlock_unlock(&f->tree_lock); + + if (res >= 0) { + if (f->conf.debug) + fprintf(stderr, " READ[%llu] %u bytes\n", + (unsigned long long)fi->fh, res); + if ((size_t) res > size) + fprintf(stderr, "fuse: read too many bytes"); + fuse_reply_buf(req, buf, res); + } else + reply_err(req, res); + + free(buf); +} + +static void fuse_lib_write(fuse_req_t req, fuse_ino_t ino, const char *buf, + size_t size, off_t off, struct fuse_file_info *fi) +{ + struct fuse *f = req_fuse_prepare(req); + char *path; + int res; + + res = -ENOENT; + pthread_rwlock_rdlock(&f->tree_lock); + path = get_path(f, ino); + if (path != NULL) { + struct fuse_intr_data d; + if (f->conf.debug) + fprintf(stderr, "WRITE%s[%llu] %lu bytes to %llu\n", + fi->writepage ? "PAGE" : "", (unsigned long long) fi->fh, + (unsigned long) size, (unsigned long long) off); + + fuse_prepare_interrupt(f, req, &d); + res = fuse_fs_write(f->fs, path, buf, size, off, fi); + fuse_finish_interrupt(f, req, &d); + free(path); + } + pthread_rwlock_unlock(&f->tree_lock); + + if (res >= 0) { + if (f->conf.debug) + fprintf(stderr, " WRITE%s[%llu] %u bytes\n", + fi->writepage ? "PAGE" : "", (unsigned long long) fi->fh, + res); + if ((size_t) res > size) + fprintf(stderr, "fuse: wrote too many bytes"); + fuse_reply_write(req, res); + } else + reply_err(req, res); +} + +static void fuse_lib_fsync(fuse_req_t req, fuse_ino_t ino, int datasync, + struct fuse_file_info *fi) +{ + struct fuse *f = req_fuse_prepare(req); + char *path; + int err; + + err = -ENOENT; + pthread_rwlock_rdlock(&f->tree_lock); + path = get_path(f, ino); + if (path != NULL) { + struct fuse_intr_data d; + if (f->conf.debug) + fprintf(stderr, "FSYNC[%llu]\n", (unsigned long long) fi->fh); + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_fsync(f->fs, path, datasync, fi); + fuse_finish_interrupt(f, req, &d); + free(path); + } + pthread_rwlock_unlock(&f->tree_lock); + reply_err(req, err); +} + +static struct fuse_dh *get_dirhandle(const struct fuse_file_info *llfi, + struct fuse_file_info *fi) +{ + struct fuse_dh *dh = (struct fuse_dh *) (uintptr_t) llfi->fh; + memset(fi, 0, sizeof(struct fuse_file_info)); + fi->fh = dh->fh; + fi->fh_old = dh->fh; + return dh; +} + +static void fuse_lib_opendir(fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *llfi) +{ + struct fuse *f = req_fuse_prepare(req); + struct fuse_intr_data d; + struct fuse_dh *dh; + struct fuse_file_info fi; + char *path; + int err; + + dh = (struct fuse_dh *) malloc(sizeof(struct fuse_dh)); + if (dh == NULL) { + reply_err(req, -ENOMEM); + return; + } + memset(dh, 0, sizeof(struct fuse_dh)); + dh->fuse = f; + dh->contents = NULL; + dh->len = 0; + dh->filled = 0; + dh->nodeid = ino; + fuse_mutex_init(&dh->lock); + + llfi->fh = (uintptr_t) dh; + + memset(&fi, 0, sizeof(fi)); + fi.flags = llfi->flags; + + err = -ENOENT; + pthread_rwlock_rdlock(&f->tree_lock); + path = get_path(f, ino); + if (path != NULL) { + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_opendir(f->fs, path, &fi); + fuse_finish_interrupt(f, req, &d); + dh->fh = fi.fh; + } + if (!err) { + if (fuse_reply_open(req, llfi) == -ENOENT) { + /* The opendir syscall was interrupted, so it must be cancelled */ + fuse_prepare_interrupt(f, req, &d); + fuse_fs_releasedir(f->fs, path, &fi); + fuse_finish_interrupt(f, req, &d); + pthread_mutex_destroy(&dh->lock); + free(dh); + } + } else { + reply_err(req, err); + pthread_mutex_destroy(&dh->lock); + free(dh); + } + free(path); + pthread_rwlock_unlock(&f->tree_lock); +} + +static int extend_contents(struct fuse_dh *dh, unsigned minsize) +{ + if (minsize > dh->size) { + char *newptr; + unsigned newsize = dh->size; + if (!newsize) + newsize = 1024; + while (newsize < minsize) { + if (newsize >= 0x80000000) + newsize = 0xffffffff; + else + newsize *= 2; + } + + newptr = (char *) realloc(dh->contents, newsize); + if (!newptr) { + dh->error = -ENOMEM; + return -1; + } + dh->contents = newptr; + dh->size = newsize; + } + return 0; +} + +static int fill_dir(void *dh_, const char *name, const struct stat *statp, + off_t off) +{ + struct fuse_dh *dh = (struct fuse_dh *) dh_; + struct stat stbuf; + size_t newlen; + + if (statp) + stbuf = *statp; + else { + memset(&stbuf, 0, sizeof(stbuf)); + stbuf.st_ino = FUSE_UNKNOWN_INO; + } + + if (!dh->fuse->conf.use_ino) { + stbuf.st_ino = FUSE_UNKNOWN_INO; + if (dh->fuse->conf.readdir_ino) { + struct node *node; + pthread_mutex_lock(&dh->fuse->lock); + node = lookup_node(dh->fuse, dh->nodeid, name); + if (node) + stbuf.st_ino = (ino_t) node->nodeid; + pthread_mutex_unlock(&dh->fuse->lock); + } + } + + if (off) { + if (extend_contents(dh, dh->needlen) == -1) + return 1; + + dh->filled = 0; + newlen = dh->len + fuse_add_direntry(dh->req, dh->contents + dh->len, + dh->needlen - dh->len, name, + &stbuf, off); + if (newlen > dh->needlen) + return 1; + } else { + newlen = dh->len + fuse_add_direntry(dh->req, NULL, 0, name, NULL, 0); + if (extend_contents(dh, newlen) == -1) + return 1; + + fuse_add_direntry(dh->req, dh->contents + dh->len, dh->size - dh->len, + name, &stbuf, newlen); + } + dh->len = newlen; + return 0; +} + +static int readdir_fill(struct fuse *f, fuse_req_t req, fuse_ino_t ino, + size_t size, off_t off, struct fuse_dh *dh, + struct fuse_file_info *fi) +{ + int err = -ENOENT; + char *path; + pthread_rwlock_rdlock(&f->tree_lock); + path = get_path(f, ino); + if (path != NULL) { + struct fuse_intr_data d; + + dh->len = 0; + dh->error = 0; + dh->needlen = size; + dh->filled = 1; + dh->req = req; + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_readdir(f->fs, path, dh, fill_dir, off, fi); + fuse_finish_interrupt(f, req, &d); + dh->req = NULL; + if (!err) + err = dh->error; + if (err) + dh->filled = 0; + free(path); + } + pthread_rwlock_unlock(&f->tree_lock); + return err; +} + +static void fuse_lib_readdir(fuse_req_t req, fuse_ino_t ino, size_t size, + off_t off, struct fuse_file_info *llfi) +{ + struct fuse *f = req_fuse_prepare(req); + struct fuse_file_info fi; + struct fuse_dh *dh = get_dirhandle(llfi, &fi); + + pthread_mutex_lock(&dh->lock); + /* According to SUS, directory contents need to be refreshed on + rewinddir() */ + if (!off) + dh->filled = 0; + + if (!dh->filled) { + int err = readdir_fill(f, req, ino, size, off, dh, &fi); + if (err) { + reply_err(req, err); + goto out; + } + } + if (dh->filled) { + if (off < dh->len) { + if (off + size > dh->len) + size = dh->len - off; + } else + size = 0; + } else { + size = dh->len; + off = 0; + } + fuse_reply_buf(req, dh->contents + off, size); + out: + pthread_mutex_unlock(&dh->lock); +} + +static void fuse_lib_releasedir(fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *llfi) +{ + struct fuse *f = req_fuse_prepare(req); + struct fuse_intr_data d; + struct fuse_file_info fi; + struct fuse_dh *dh = get_dirhandle(llfi, &fi); + char *path; + + pthread_rwlock_rdlock(&f->tree_lock); + path = get_path(f, ino); + fuse_prepare_interrupt(f, req, &d); + fuse_fs_releasedir(f->fs, path ? path : "-", &fi); + fuse_finish_interrupt(f, req, &d); + if (path) + free(path); + pthread_rwlock_unlock(&f->tree_lock); + pthread_mutex_lock(&dh->lock); + pthread_mutex_unlock(&dh->lock); + pthread_mutex_destroy(&dh->lock); + free(dh->contents); + free(dh); + reply_err(req, 0); +} + +static void fuse_lib_fsyncdir(fuse_req_t req, fuse_ino_t ino, int datasync, + struct fuse_file_info *llfi) +{ + struct fuse *f = req_fuse_prepare(req); + struct fuse_file_info fi; + char *path; + int err; + + get_dirhandle(llfi, &fi); + + err = -ENOENT; + pthread_rwlock_rdlock(&f->tree_lock); + path = get_path(f, ino); + if (path != NULL) { + struct fuse_intr_data d; + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_fsyncdir(f->fs, path, datasync, &fi); + fuse_finish_interrupt(f, req, &d); + free(path); + } + pthread_rwlock_unlock(&f->tree_lock); + reply_err(req, err); +} + +static void fuse_lib_statfs(fuse_req_t req, fuse_ino_t ino) +{ + struct fuse *f = req_fuse_prepare(req); + +#if HAVE_SYS_STATVFS_H + struct statvfs buf; + char *path; + int err; + + memset(&buf, 0, sizeof(buf)); + pthread_rwlock_rdlock(&f->tree_lock); + if (!ino) { + err = -ENOMEM; + path = strdup("/"); + } else { + err = -ENOENT; + path = get_path(f, ino); + } + if (path) { + struct fuse_intr_data d; + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_statfs(f->fs, path, &buf); + fuse_finish_interrupt(f, req, &d); + free(path); + } + pthread_rwlock_unlock(&f->tree_lock); + + if (!err) + fuse_reply_statfs(req, &buf); + else + reply_err(req, err); +#endif +} + +static void fuse_lib_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name, + const char *value, size_t size, int flags) +{ + struct fuse *f = req_fuse_prepare(req); + char *path; + int err; + + err = -ENOENT; + pthread_rwlock_rdlock(&f->tree_lock); + path = get_path(f, ino); + if (path != NULL) { + struct fuse_intr_data d; + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_setxattr(f->fs, path, name, value, size, flags); + fuse_finish_interrupt(f, req, &d); + free(path); + } + pthread_rwlock_unlock(&f->tree_lock); + reply_err(req, err); +} + +static int common_getxattr(struct fuse *f, fuse_req_t req, fuse_ino_t ino, + const char *name, char *value, size_t size) +{ + int err; + char *path; + + err = -ENOENT; + pthread_rwlock_rdlock(&f->tree_lock); + path = get_path(f, ino); + if (path != NULL) { + struct fuse_intr_data d; + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_getxattr(f->fs, path, name, value, size); + fuse_finish_interrupt(f, req, &d); + free(path); + } + pthread_rwlock_unlock(&f->tree_lock); + return err; +} + +static void fuse_lib_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name, + size_t size) +{ + struct fuse *f = req_fuse_prepare(req); + int res; + + if (size) { + char *value = (char *) malloc(size); + if (value == NULL) { + reply_err(req, -ENOMEM); + return; + } + res = common_getxattr(f, req, ino, name, value, size); + if (res > 0) + fuse_reply_buf(req, value, res); + else + reply_err(req, res); + free(value); + } else { + res = common_getxattr(f, req, ino, name, NULL, 0); + if (res >= 0) + fuse_reply_xattr(req, res); + else + reply_err(req, res); + } +} + +static int common_listxattr(struct fuse *f, fuse_req_t req, fuse_ino_t ino, + char *list, size_t size) +{ + char *path; + int err; + + err = -ENOENT; + pthread_rwlock_rdlock(&f->tree_lock); + path = get_path(f, ino); + if (path != NULL) { + struct fuse_intr_data d; + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_listxattr(f->fs, path, list, size); + fuse_finish_interrupt(f, req, &d); + free(path); + } + pthread_rwlock_unlock(&f->tree_lock); + return err; +} + +static void fuse_lib_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size) +{ + struct fuse *f = req_fuse_prepare(req); + int res; + + if (size) { + char *list = (char *) malloc(size); + if (list == NULL) { + reply_err(req, -ENOMEM); + return; + } + res = common_listxattr(f, req, ino, list, size); + if (res > 0) + fuse_reply_buf(req, list, res); + else + reply_err(req, res); + free(list); + } else { + res = common_listxattr(f, req, ino, NULL, 0); + if (res >= 0) + fuse_reply_xattr(req, res); + else + reply_err(req, res); + } +} + +static void fuse_lib_removexattr(fuse_req_t req, fuse_ino_t ino, + const char *name) +{ + struct fuse *f = req_fuse_prepare(req); + char *path; + int err; + + err = -ENOENT; + pthread_rwlock_rdlock(&f->tree_lock); + path = get_path(f, ino); + if (path != NULL) { + struct fuse_intr_data d; + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_removexattr(f->fs, path, name); + fuse_finish_interrupt(f, req, &d); + free(path); + } + pthread_rwlock_unlock(&f->tree_lock); + reply_err(req, err); +} + +static struct lock *locks_conflict(struct node *node, const struct lock *lock) +{ + struct lock *l; + + for (l = node->locks; l; l = l->next) + if (l->owner != lock->owner && + lock->start <= l->end && l->start <= lock->end && + (l->type == F_WRLCK || lock->type == F_WRLCK)) + break; + + return l; +} + +static void delete_lock(struct lock **lockp) +{ + struct lock *l = *lockp; + *lockp = l->next; + free(l); +} + +static void insert_lock(struct lock **pos, struct lock *lock) +{ + lock->next = *pos; + *pos = lock; +} + +static int locks_insert(struct node *node, struct lock *lock) +{ + struct lock **lp; + struct lock *newl1 = NULL; + struct lock *newl2 = NULL; + + if (lock->type != F_UNLCK || lock->start != 0 || lock->end != OFFSET_MAX) { + newl1 = malloc(sizeof(struct lock)); + newl2 = malloc(sizeof(struct lock)); + + if (!newl1 || !newl2) { + free(newl1); + free(newl2); + return -ENOLCK; + } + } + + for (lp = &node->locks; *lp;) { + struct lock *l = *lp; + if (l->owner != lock->owner) + goto skip; + + if (lock->type == l->type) { + if (l->end < lock->start - 1) + goto skip; + if (lock->end < l->start - 1) + break; + if (l->start <= lock->start && lock->end <= l->end) + goto out; + if (l->start < lock->start) + lock->start = l->start; + if (lock->end < l->end) + lock->end = l->end; + goto delete; + } else { + if (l->end < lock->start) + goto skip; + if (lock->end < l->start) + break; + if (lock->start <= l->start && l->end <= lock->end) + goto delete; + if (l->end <= lock->end) { + l->end = lock->start - 1; + goto skip; + } + if (lock->start <= l->start) { + l->start = lock->end + 1; + break; + } + *newl2 = *l; + newl2->start = lock->end + 1; + l->end = lock->start - 1; + insert_lock(&l->next, newl2); + newl2 = NULL; + } + skip: + lp = &l->next; + continue; + + delete: + delete_lock(lp); + } + if (lock->type != F_UNLCK) { + *newl1 = *lock; + insert_lock(lp, newl1); + newl1 = NULL; + } +out: + free(newl1); + free(newl2); + return 0; +} + +static void flock_to_lock(struct flock *flock, struct lock *lock) +{ + memset(lock, 0, sizeof(struct lock)); + lock->type = flock->l_type; + lock->start = flock->l_start; + lock->end = flock->l_len ? flock->l_start + flock->l_len - 1 : OFFSET_MAX; + lock->pid = flock->l_pid; +} + +static void lock_to_flock(struct lock *lock, struct flock *flock) +{ + flock->l_type = lock->type; + flock->l_start = lock->start; + flock->l_len = (lock->end == OFFSET_MAX) ? 0 : lock->end - lock->start + 1; + flock->l_pid = lock->pid; +} + +static int fuse_flush_common(struct fuse *f, fuse_req_t req, fuse_ino_t ino, + const char *path, struct fuse_file_info *fi) +{ + struct fuse_intr_data d; + struct flock lock; + struct lock l; + int err; + int errlock; + + fuse_prepare_interrupt(f, req, &d); + memset(&lock, 0, sizeof(lock)); + lock.l_type = F_UNLCK; + lock.l_whence = SEEK_SET; + err = fuse_fs_flush(f->fs, path, fi); + errlock = fuse_fs_lock(f->fs, path, fi, F_SETLK, &lock); + fuse_finish_interrupt(f, req, &d); + + if (errlock != -ENOSYS) { + flock_to_lock(&lock, &l); + l.owner = fi->lock_owner; + pthread_mutex_lock(&f->lock); + locks_insert(get_node(f, ino), &l); + pthread_mutex_unlock(&f->lock); + + /* if op.lock() is defined FLUSH is needed regardless of op.flush() */ + if (err == -ENOSYS) + err = 0; + } + return err; +} + +static void fuse_lib_release(fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *fi) +{ + struct fuse *f = req_fuse_prepare(req); + struct fuse_intr_data d; + char *path; + int err = 0; + + pthread_rwlock_rdlock(&f->tree_lock); + path = get_path(f, ino); + if (f->conf.debug) + fprintf(stderr, "RELEASE%s[%llu] flags: 0x%x\n", + fi->flush ? "+FLUSH" : "", + (unsigned long long) fi->fh, fi->flags); + + if (fi->flush) { + err = fuse_flush_common(f, req, ino, path, fi); + if (err == -ENOSYS) + err = 0; + } + + fuse_prepare_interrupt(f, req, &d); + fuse_do_release(f, ino, path, fi); + fuse_finish_interrupt(f, req, &d); + free(path); + pthread_rwlock_unlock(&f->tree_lock); + + reply_err(req, err); +} + +static void fuse_lib_flush(fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *fi) +{ + struct fuse *f = req_fuse_prepare(req); + char *path; + int err; + + pthread_rwlock_rdlock(&f->tree_lock); + path = get_path(f, ino); + if (path && f->conf.debug) + fprintf(stderr, "FLUSH[%llu]\n", (unsigned long long) fi->fh); + err = fuse_flush_common(f, req, ino, path, fi); + free(path); + pthread_rwlock_unlock(&f->tree_lock); + reply_err(req, err); +} + +static int fuse_lock_common(fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *fi, struct flock *lock, + int cmd) +{ + struct fuse *f = req_fuse_prepare(req); + char *path; + int err; + + err = -ENOENT; + pthread_rwlock_rdlock(&f->tree_lock); + path = get_path(f, ino); + if (path != NULL) { + struct fuse_intr_data d; + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_lock(f->fs, path, fi, cmd, lock); + fuse_finish_interrupt(f, req, &d); + free(path); + } + pthread_rwlock_unlock(&f->tree_lock); + return err; +} + +static void fuse_lib_getlk(fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *fi, struct flock *lock) +{ + int err; + struct lock l; + struct lock *conflict; + struct fuse *f = req_fuse(req); + + flock_to_lock(lock, &l); + l.owner = fi->lock_owner; + pthread_mutex_lock(&f->lock); + conflict = locks_conflict(get_node(f, ino), &l); + if (conflict) + lock_to_flock(conflict, lock); + pthread_mutex_unlock(&f->lock); + if (!conflict) + err = fuse_lock_common(req, ino, fi, lock, F_GETLK); + else + err = 0; + + if (!err) + fuse_reply_lock(req, lock); + else + reply_err(req, err); +} + +static void fuse_lib_setlk(fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *fi, struct flock *lock, + int should_sleep) +{ + int err = fuse_lock_common(req, ino, fi, lock, should_sleep ? F_SETLKW : F_SETLK); + if (!err) { + struct fuse *f = req_fuse(req); + struct lock l; + flock_to_lock(lock, &l); + l.owner = fi->lock_owner; + pthread_mutex_lock(&f->lock); + locks_insert(get_node(f, ino), &l); + pthread_mutex_unlock(&f->lock); + } + reply_err(req, err); +} + +static void fuse_lib_bmap(fuse_req_t req, fuse_ino_t ino, size_t blocksize, + uint64_t idx) +{ + struct fuse *f = req_fuse_prepare(req); + struct fuse_intr_data d; + char *path; + int err; + + err = -ENOENT; + pthread_rwlock_rdlock(&f->tree_lock); + path = get_path(f, ino); + if (path != NULL) { + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_bmap(f->fs, path, blocksize, &idx); + fuse_finish_interrupt(f, req, &d); + free(path); + } + pthread_rwlock_unlock(&f->tree_lock); + if (!err) + fuse_reply_bmap(req, idx); + else + reply_err(req, err); +} + +static struct fuse_lowlevel_ops fuse_path_ops = { + .init = fuse_lib_init, + .destroy = fuse_lib_destroy, + .lookup = fuse_lib_lookup, + .forget = fuse_lib_forget, + .getattr = fuse_lib_getattr, + .setattr = fuse_lib_setattr, + .access = fuse_lib_access, + .readlink = fuse_lib_readlink, + .mknod = fuse_lib_mknod, + .mkdir = fuse_lib_mkdir, + .unlink = fuse_lib_unlink, + .rmdir = fuse_lib_rmdir, + .symlink = fuse_lib_symlink, + .rename = fuse_lib_rename, + .link = fuse_lib_link, + .create = fuse_lib_create, + .open = fuse_lib_open, + .read = fuse_lib_read, + .write = fuse_lib_write, + .flush = fuse_lib_flush, + .release = fuse_lib_release, + .fsync = fuse_lib_fsync, + .opendir = fuse_lib_opendir, + .readdir = fuse_lib_readdir, + .releasedir = fuse_lib_releasedir, + .fsyncdir = fuse_lib_fsyncdir, + .statfs = fuse_lib_statfs, + .setxattr = fuse_lib_setxattr, + .getxattr = fuse_lib_getxattr, + .listxattr = fuse_lib_listxattr, + .removexattr = fuse_lib_removexattr, + .getlk = fuse_lib_getlk, + .setlk = fuse_lib_setlk, + .bmap = fuse_lib_bmap, +}; + +struct fuse_session *fuse_get_session(struct fuse *f) +{ + return f->se; +} + +int fuse_loop(struct fuse *f) +{ + if (f) + return fuse_session_loop(f->se); + else + return -1; +} + +void fuse_exit(struct fuse *f) +{ + fuse_session_exit(f->se); +} + +struct fuse_context *fuse_get_context(void) +{ + return &fuse_get_context_internal()->ctx; +} + +int fuse_interrupted(void) +{ + return fuse_req_interrupted(fuse_get_context_internal()->req); +} + +enum { + KEY_HELP, +}; + +#define FUSE_LIB_OPT(t, p, v) { t, offsetof(struct fuse_config, p), v } + +static const struct fuse_opt fuse_lib_opts[] = { + FUSE_OPT_KEY("-h", KEY_HELP), + FUSE_OPT_KEY("--help", KEY_HELP), + FUSE_OPT_KEY("debug", FUSE_OPT_KEY_KEEP), + FUSE_OPT_KEY("-d", FUSE_OPT_KEY_KEEP), + FUSE_LIB_OPT("debug", debug, 1), + FUSE_LIB_OPT("-d", debug, 1), + FUSE_LIB_OPT("hard_remove", hard_remove, 1), + FUSE_LIB_OPT("use_ino", use_ino, 1), + FUSE_LIB_OPT("readdir_ino", readdir_ino, 1), + FUSE_LIB_OPT("direct_io", direct_io, 1), + FUSE_LIB_OPT("kernel_cache", kernel_cache, 1), + FUSE_LIB_OPT("umask=", set_mode, 1), + FUSE_LIB_OPT("umask=%o", umask, 0), + FUSE_LIB_OPT("uid=", set_uid, 1), + FUSE_LIB_OPT("uid=%d", uid, 0), + FUSE_LIB_OPT("gid=", set_gid, 1), + FUSE_LIB_OPT("gid=%d", gid, 0), + FUSE_LIB_OPT("entry_timeout=%lf", entry_timeout, 0), + FUSE_LIB_OPT("attr_timeout=%lf", attr_timeout, 0), + FUSE_LIB_OPT("ac_attr_timeout=%lf", ac_attr_timeout, 0), + FUSE_LIB_OPT("ac_attr_timeout=", ac_attr_timeout_set, 1), + FUSE_LIB_OPT("negative_timeout=%lf", negative_timeout, 0), + FUSE_LIB_OPT("intr", intr, 1), + FUSE_LIB_OPT("intr_signal=%d", intr_signal, 0), + FUSE_OPT_END +}; + +static void fuse_lib_help(void) +{ + fprintf(stderr, +" -o hard_remove immediate removal (don't hide files)\n" +" -o use_ino let filesystem set inode numbers\n" +" -o readdir_ino try to fill in d_ino in readdir\n" +" -o direct_io use direct I/O\n" +" -o kernel_cache cache files in kernel\n" +" -o umask=M set file permissions (octal)\n" +" -o uid=N set file owner\n" +" -o gid=N set file group\n" +" -o entry_timeout=T cache timeout for names (1.0s)\n" +" -o negative_timeout=T cache timeout for deleted names (0.0s)\n" +" -o attr_timeout=T cache timeout for attributes (1.0s)\n" +" -o ac_attr_timeout=T auto cache timeout for attributes (attr_timeout)\n" +" -o intr allow requests to be interrupted\n" +" -o intr_signal=NUM signal to send on interrupt (%i)\n" +"\n", FUSE_DEFAULT_INTR_SIGNAL); +} + +static int fuse_lib_opt_proc(void *data, const char *arg, int key, + struct fuse_args *outargs) +{ + (void) arg; (void) outargs; + + if (key == KEY_HELP) { + struct fuse_config *conf = (struct fuse_config *) data; + fuse_lib_help(); + conf->help = 1; + } + + return 1; +} + +static int fuse_init_intr_signal(int signum, int *installed) +{ + struct sigaction old_sa; + + if (sigaction(signum, NULL, &old_sa) == -1) { + perror("fuse: cannot get old signal handler"); + return -1; + } + + if (old_sa.sa_handler == SIG_DFL) { + struct sigaction sa; + + memset(&sa, 0, sizeof(struct sigaction)); + sa.sa_handler = fuse_intr_sighandler; + sigemptyset(&sa.sa_mask); + + if (sigaction(signum, &sa, NULL) == -1) { + perror("fuse: cannot set interrupt signal handler"); + return -1; + } + *installed = 1; + } + return 0; +} + +static void fuse_restore_intr_signal(int signum) +{ + struct sigaction sa; + + memset(&sa, 0, sizeof(struct sigaction)); + sa.sa_handler = SIG_DFL; + sigaction(signum, &sa, NULL); +} + +struct fuse_fs *fuse_fs_new(const struct fuse_operations *op, size_t op_size, + void *user_data) +{ + struct fuse_fs *fs; + + if (sizeof(struct fuse_operations) < op_size) { + fprintf(stderr, "fuse: warning: library too old, some operations may not not work\n"); + op_size = sizeof(struct fuse_operations); + } + + fs = (struct fuse_fs *) calloc(1, sizeof(struct fuse_fs)); + if (!fs) { + fprintf(stderr, "fuse: failed to allocate fuse_fs object\n"); + return NULL; + } + + fs->user_data = user_data; + if (op) + memcpy(&fs->op, op, op_size); + return fs; +} + +struct fuse *fuse_new(struct fuse_chan *ch, struct fuse_args *args, + const struct fuse_operations *op, size_t op_size, + void *user_data) +{ + struct fuse *f; + struct node *root; + struct fuse_fs *fs; + struct fuse_lowlevel_ops llop = fuse_path_ops; + + if (fuse_create_context_key() == -1) + goto out; + + f = (struct fuse *) calloc(1, sizeof(struct fuse)); + if (f == NULL) { + fprintf(stderr, "fuse: failed to allocate fuse object\n"); + goto out_delete_context_key; + } + + fs = fuse_fs_new(op, op_size, user_data); + if (!fs) + goto out_free; + + f->fs = fs; + f->utime_omit_ok = fs->op.flag_utime_omit_ok; + + /* Oh f**k, this is ugly! */ + if (!fs->op.lock) { + llop.getlk = NULL; + llop.setlk = NULL; + } + +// f->conf.direct_io = 1; + f->conf.entry_timeout = 1.0; + f->conf.attr_timeout = 1.0; + f->conf.negative_timeout = 0.0; + f->conf.intr_signal = FUSE_DEFAULT_INTR_SIGNAL; + + if (fuse_opt_parse(args, &f->conf, fuse_lib_opts, fuse_lib_opt_proc) == -1) + goto out_free_fs; + + if (!f->conf.ac_attr_timeout_set) + f->conf.ac_attr_timeout = f->conf.attr_timeout; + +#ifdef __FreeBSD__ + /* + * In FreeBSD, we always use these settings as inode numbers are needed to + * make getcwd(3) work. + */ + f->conf.readdir_ino = 1; +#endif + + f->se = fuse_lowlevel_new(args, &llop, sizeof(llop), f); + if (f->se == NULL) { + goto out_free_fs; + } + + fuse_session_add_chan(f->se, ch); + + if (f->conf.debug) + fprintf(stderr, "utime_omit_ok: %i\n", f->utime_omit_ok); + f->ctr = 0; + f->generation = 0; + /* FIXME: Dynamic hash table */ + f->name_table_size = 14057; + f->name_table = (struct node **) + calloc(1, sizeof(struct node *) * f->name_table_size); + if (f->name_table == NULL) { + fprintf(stderr, "fuse: memory allocation failed\n"); + goto out_free_session; + } + + f->id_table_size = 14057; + f->id_table = (struct node **) + calloc(1, sizeof(struct node *) * f->id_table_size); + if (f->id_table == NULL) { + fprintf(stderr, "fuse: memory allocation failed\n"); + goto out_free_name_table; + } + + fuse_mutex_init(&f->lock); + pthread_rwlock_init(&f->tree_lock, NULL); + + root = (struct node *) calloc(1, sizeof(struct node)); + if (root == NULL) { + fprintf(stderr, "fuse: memory allocation failed\n"); + goto out_free_id_table; + } + + root->name = strdup("/"); + if (root->name == NULL) { + fprintf(stderr, "fuse: memory allocation failed\n"); + goto out_free_root; + } + + if (f->conf.intr && + fuse_init_intr_signal(f->conf.intr_signal, &f->intr_installed) == -1) + goto out_free_root_name; + + root->parent = NULL; + root->nodeid = FUSE_ROOT_ID; + root->generation = 0; + root->refctr = 1; + root->nlookup = 1; + hash_id(f, root); + + return f; + + out_free_root_name: + free(root->name); + out_free_root: + free(root); + out_free_id_table: + free(f->id_table); + out_free_name_table: + free(f->name_table); + out_free_session: + fuse_session_destroy(f->se); + out_free_fs: + /* Horrible compatibility hack to stop the destructor from being + called on the filesystem without init being called first */ + fs->op.destroy = NULL; + fuse_fs_destroy(f->fs); + out_free: + free(f); + out_delete_context_key: + fuse_delete_context_key(); + out: + return NULL; +} + +void fuse_destroy(struct fuse *f) +{ + size_t i; + + if (f->conf.intr && f->intr_installed) + fuse_restore_intr_signal(f->conf.intr_signal); + + if (f->fs) { + struct fuse_context_i *c = fuse_get_context_internal(); + + memset(c, 0, sizeof(*c)); + c->ctx.fuse = f; + + for (i = 0; i < f->id_table_size; i++) { + struct node *node; + + for (node = f->id_table[i]; node != NULL; node = node->id_next) { + if (node->is_hidden) { + char *path = get_path(f, node->nodeid); + if (path) { + fuse_fs_unlink(f->fs, path); + free(path); + } + } + } + } + } + for (i = 0; i < f->id_table_size; i++) { + struct node *node; + struct node *next; + + for (node = f->id_table[i]; node != NULL; node = next) { + next = node->id_next; + free_node(node); + } + } + free(f->id_table); + free(f->name_table); + pthread_mutex_destroy(&f->lock); + pthread_rwlock_destroy(&f->tree_lock); + fuse_session_destroy(f->se); + free(f); + fuse_delete_context_key(); +} + diff --git a/libfuse-lite/fuse_i.h b/libfuse-lite/fuse_i.h new file mode 100755 index 0000000..38c45c7 --- a/dev/null +++ b/libfuse-lite/fuse_i.h @@ -0,0 +1,25 @@ +/* + FUSE: Filesystem in Userspace + Copyright (C) 2001-2007 Miklos Szeredi + + This program can be distributed under the terms of the GNU LGPLv2. + See the file COPYING.LIB +*/ + +#include "fuse.h" + +struct fuse_session; +struct fuse_chan; +struct fuse_lowlevel_ops; +struct fuse_req; + +struct fuse_cmd { + char *buf; + size_t buflen; + struct fuse_chan *ch; +}; + +struct fuse_chan *fuse_kern_chan_new(int fd); + +void fuse_kern_unmount(const char *mountpoint, int fd); +int fuse_kern_mount(const char *mountpoint, struct fuse_args *args); diff --git a/libfuse-lite/fuse_kern_chan.c b/libfuse-lite/fuse_kern_chan.c new file mode 100755 index 0000000..0afec4b --- a/dev/null +++ b/libfuse-lite/fuse_kern_chan.c @@ -0,0 +1,96 @@ +/* + FUSE: Filesystem in Userspace + Copyright (C) 2001-2007 Miklos Szeredi + + This program can be distributed under the terms of the GNU LGPLv2. + See the file COPYING.LIB +*/ + +#include "config.h" +#include "fuse_lowlevel.h" +#include "fuse_kernel.h" +#include "fuse_i.h" + +#include +#include +#include +#include + +static int fuse_kern_chan_receive(struct fuse_chan **chp, char *buf, + size_t size) +{ + struct fuse_chan *ch = *chp; + int err; + ssize_t res; + struct fuse_session *se = fuse_chan_session(ch); + assert(se != NULL); + + restart: + res = read(fuse_chan_fd(ch), buf, size); + err = errno; + + if (fuse_session_exited(se)) + return 0; + if (res == -1) { + /* ENOENT means the operation was interrupted, it's safe + to restart */ + if (err == ENOENT) + goto restart; + + if (err == ENODEV) { + fuse_session_exit(se); + return 0; + } + /* Errors occuring during normal operation: EINTR (read + interrupted), EAGAIN (nonblocking I/O), ENODEV (filesystem + umounted) */ + if (err != EINTR && err != EAGAIN) + perror("fuse: reading device"); + return -err; + } + if ((size_t) res < sizeof(struct fuse_in_header)) { + fprintf(stderr, "short read on fuse device\n"); + return -EIO; + } + return res; +} + +static int fuse_kern_chan_send(struct fuse_chan *ch, const struct iovec iov[], + size_t count) +{ + if (iov) { + ssize_t res = writev(fuse_chan_fd(ch), iov, count); + int err = errno; + + if (res == -1) { + struct fuse_session *se = fuse_chan_session(ch); + + assert(se != NULL); + + /* ENOENT means the operation was interrupted */ + if (!fuse_session_exited(se) && err != ENOENT) + perror("fuse: writing device"); + return -err; + } + } + return 0; +} + +static void fuse_kern_chan_destroy(struct fuse_chan *ch) +{ + close(fuse_chan_fd(ch)); +} + +#define MIN_BUFSIZE 0x101000 + +struct fuse_chan *fuse_kern_chan_new(int fd) +{ + struct fuse_chan_ops op = { + .receive = fuse_kern_chan_receive, + .send = fuse_kern_chan_send, + .destroy = fuse_kern_chan_destroy, + }; + size_t bufsize = getpagesize() + 0x1000; + bufsize = bufsize < MIN_BUFSIZE ? MIN_BUFSIZE : bufsize; + return fuse_chan_new(&op, fd, bufsize, NULL); +} diff --git a/libfuse-lite/fuse_loop.c b/libfuse-lite/fuse_loop.c new file mode 100755 index 0000000..0b592e5 --- a/dev/null +++ b/libfuse-lite/fuse_loop.c @@ -0,0 +1,40 @@ +/* + FUSE: Filesystem in Userspace + Copyright (C) 2001-2007 Miklos Szeredi + + This program can be distributed under the terms of the GNU LGPLv2. + See the file COPYING.LIB +*/ + +#include "config.h" +#include "fuse_lowlevel.h" + +#include +#include +#include + +int fuse_session_loop(struct fuse_session *se) +{ + int res = 0; + struct fuse_chan *ch = fuse_session_next_chan(se, NULL); + size_t bufsize = fuse_chan_bufsize(ch); + char *buf = (char *) malloc(bufsize); + if (!buf) { + fprintf(stderr, "fuse: failed to allocate read buffer\n"); + return -1; + } + + while (!fuse_session_exited(se)) { + struct fuse_chan *tmpch = ch; + res = fuse_chan_recv(&tmpch, buf, bufsize); + if (res == -EINTR) + continue; + if (res <= 0) + break; + fuse_session_process(se, buf, res, tmpch); + } + + free(buf); + fuse_session_reset(se); + return res < 0 ? -1 : 0; +} diff --git a/libfuse-lite/fuse_lowlevel.c b/libfuse-lite/fuse_lowlevel.c new file mode 100755 index 0000000..f6530c1 --- a/dev/null +++ b/libfuse-lite/fuse_lowlevel.c @@ -0,0 +1,1395 @@ +/* + FUSE: Filesystem in Userspace + Copyright (C) 2001-2007 Miklos Szeredi + + This program can be distributed under the terms of the GNU LGPLv2. + See the file COPYING.LIB +*/ + +#include "config.h" +#include "fuse_lowlevel.h" +#include "fuse_kernel.h" +#include "fuse_opt.h" +#include "fuse_i.h" +#include "fuse_misc.h" +#include "fuse_lowlevel_compat.h" + +#include +#include +#include +#include +#include +#include +#include + +#define PARAM(inarg) (((const char *)(inarg)) + sizeof(*(inarg))) +#define OFFSET_MAX 0x7fffffffffffffffLL + +struct fuse_ll; + +struct fuse_req { + struct fuse_ll *f; + uint64_t unique; + int ctr; + pthread_mutex_t lock; + struct fuse_ctx ctx; + struct fuse_chan *ch; + int interrupted; + union { + struct { + uint64_t unique; + } i; + struct { + fuse_interrupt_func_t func; + void *data; + } ni; + } u; + struct fuse_req *next; + struct fuse_req *prev; +}; + +struct fuse_ll { + int debug; + int allow_root; + struct fuse_lowlevel_ops op; + int got_init; + void *userdata; + uid_t owner; + struct fuse_conn_info conn; + struct fuse_req list; + struct fuse_req interrupts; + pthread_mutex_t lock; + int got_destroy; +}; + +static void convert_stat(const struct stat *stbuf, struct fuse_attr *attr) +{ + attr->ino = stbuf->st_ino; + attr->mode = stbuf->st_mode; + attr->nlink = stbuf->st_nlink; + attr->uid = stbuf->st_uid; + attr->gid = stbuf->st_gid; + attr->rdev = stbuf->st_rdev; + attr->size = stbuf->st_size; + attr->blocks = stbuf->st_blocks; + attr->atime = stbuf->st_atime; + attr->mtime = stbuf->st_mtime; + attr->ctime = stbuf->st_ctime; + attr->atimensec = ST_ATIM_NSEC(stbuf); + attr->mtimensec = ST_MTIM_NSEC(stbuf); + attr->ctimensec = ST_CTIM_NSEC(stbuf); +#ifdef POSIXACLS + attr->filling = 0; /* JPA trying to be safe */ +#endif +} + +static void convert_attr(const struct fuse_setattr_in *attr, struct stat *stbuf) +{ + stbuf->st_mode = attr->mode; + stbuf->st_uid = attr->uid; + stbuf->st_gid = attr->gid; + stbuf->st_size = attr->size; + stbuf->st_atime = attr->atime; + stbuf->st_mtime = attr->mtime; + ST_ATIM_NSEC_SET(stbuf, attr->atimensec); + ST_MTIM_NSEC_SET(stbuf, attr->mtimensec); +} + +static size_t iov_length(const struct iovec *iov, size_t count) +{ + size_t seg; + size_t ret = 0; + + for (seg = 0; seg < count; seg++) + ret += iov[seg].iov_len; + return ret; +} + +static void list_init_req(struct fuse_req *req) +{ + req->next = req; + req->prev = req; +} + +static void list_del_req(struct fuse_req *req) +{ + struct fuse_req *prev = req->prev; + struct fuse_req *next = req->next; + prev->next = next; + next->prev = prev; +} + +static void list_add_req(struct fuse_req *req, struct fuse_req *next) +{ + struct fuse_req *prev = next->prev; + req->next = next; + req->prev = prev; + prev->next = req; + next->prev = req; +} + +static void destroy_req(fuse_req_t req) +{ + pthread_mutex_destroy(&req->lock); + free(req); +} + +static void free_req(fuse_req_t req) +{ + int ctr; + struct fuse_ll *f = req->f; + + pthread_mutex_lock(&req->lock); + req->u.ni.func = NULL; + req->u.ni.data = NULL; + pthread_mutex_unlock(&req->lock); + + pthread_mutex_lock(&f->lock); + list_del_req(req); + ctr = --req->ctr; + pthread_mutex_unlock(&f->lock); + if (!ctr) + destroy_req(req); +} + +static int send_reply_iov(fuse_req_t req, int error, struct iovec *iov, + int count) +{ + struct fuse_out_header out; + int res; + + if (error <= -1000 || error > 0) { + fprintf(stderr, "fuse: bad error value: %i\n", error); + error = -ERANGE; + } + + out.unique = req->unique; + out.error = error; + iov[0].iov_base = &out; + iov[0].iov_len = sizeof(struct fuse_out_header); + out.len = iov_length(iov, count); + + if (req->f->debug) + fprintf(stderr, " unique: %llu, error: %i (%s), outsize: %i\n", + (unsigned long long) out.unique, out.error, + strerror(-out.error), out.len); + res = fuse_chan_send(req->ch, iov, count); + free_req(req); + + return res; +} + +static int send_reply(fuse_req_t req, int error, const void *arg, + size_t argsize) +{ + struct iovec iov[2]; + int count = 1; + if (argsize) { + iov[1].iov_base = (void *) arg; + iov[1].iov_len = argsize; + count++; + } + return send_reply_iov(req, error, iov, count); +} + +int fuse_reply_iov(fuse_req_t req, const struct iovec *iov, int count) +{ + int res; + struct iovec *padded_iov; + + padded_iov = malloc((count + 1) * sizeof(struct iovec)); + if (padded_iov == NULL) + return fuse_reply_err(req, -ENOMEM); + + memcpy(padded_iov + 1, iov, count * sizeof(struct iovec)); + count++; + + res = send_reply_iov(req, 0, padded_iov, count); + free(padded_iov); + + return res; +} + +size_t fuse_dirent_size(size_t namelen) +{ + return FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + namelen); +} + +char *fuse_add_dirent(char *buf, const char *name, const struct stat *stbuf, + off_t off) +{ + unsigned namelen = strlen(name); + unsigned entlen = FUSE_NAME_OFFSET + namelen; + unsigned entsize = fuse_dirent_size(namelen); + unsigned padlen = entsize - entlen; + struct fuse_dirent *dirent = (struct fuse_dirent *) buf; + + dirent->ino = stbuf->st_ino; + dirent->off = off; + dirent->namelen = namelen; + dirent->type = (stbuf->st_mode & 0170000) >> 12; + strncpy(dirent->name, name, namelen); + if (padlen) + memset(buf + entlen, 0, padlen); + + return buf + entsize; +} + +size_t fuse_add_direntry(fuse_req_t req, char *buf, size_t bufsize, + const char *name, const struct stat *stbuf, off_t off) +{ + size_t entsize; + + (void) req; + entsize = fuse_dirent_size(strlen(name)); + if (entsize <= bufsize && buf) + fuse_add_dirent(buf, name, stbuf, off); + return entsize; +} + +#if HAVE_SYS_STATVFS_H + +static void convert_statfs(const struct statvfs *stbuf, + struct fuse_kstatfs *kstatfs) +{ + kstatfs->bsize = stbuf->f_bsize; + kstatfs->frsize = stbuf->f_frsize; + kstatfs->blocks = stbuf->f_blocks; + kstatfs->bfree = stbuf->f_bfree; + kstatfs->bavail = stbuf->f_bavail; + kstatfs->files = stbuf->f_files; + kstatfs->ffree = stbuf->f_ffree; + kstatfs->namelen = stbuf->f_namemax; +} +#endif + + +static int send_reply_ok(fuse_req_t req, const void *arg, size_t argsize) +{ + return send_reply(req, 0, arg, argsize); +} + +int fuse_reply_err(fuse_req_t req, int err) +{ + return send_reply(req, -err, NULL, 0); +} + +void fuse_reply_none(fuse_req_t req) +{ + fuse_chan_send(req->ch, NULL, 0); + free_req(req); +} + +static unsigned long calc_timeout_sec(double t) +{ + if (t > (double) ULONG_MAX) + return ULONG_MAX; + else if (t < 0.0) + return 0; + else + return (unsigned long) t; +} + +static unsigned int calc_timeout_nsec(double t) +{ + unsigned long secs = calc_timeout_sec(t); + double f = t - (double)secs; + if (f < 0.0) + return 0; + else if (f >= 0.999999999) + return 999999999; + else + return (unsigned int) (f * 1.0e9); +} + +static void fill_entry(struct fuse_entry_out *arg, + const struct fuse_entry_param *e) +{ + arg->nodeid = e->ino; + arg->generation = e->generation; + arg->entry_valid = calc_timeout_sec(e->entry_timeout); + arg->entry_valid_nsec = calc_timeout_nsec(e->entry_timeout); + arg->attr_valid = calc_timeout_sec(e->attr_timeout); + arg->attr_valid_nsec = calc_timeout_nsec(e->attr_timeout); + convert_stat(&e->attr, &arg->attr); +} + +static void fill_open(struct fuse_open_out *arg, + const struct fuse_file_info *f) +{ + arg->fh = f->fh; + if (f->direct_io) + arg->open_flags |= FOPEN_DIRECT_IO; + if (f->keep_cache) + arg->open_flags |= FOPEN_KEEP_CACHE; +} + +int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e) +{ + struct fuse_entry_out arg; + + /* before ABI 7.4 e->ino == 0 was invalid, only ENOENT meant + negative entry */ + if (!e->ino && req->f->conn.proto_minor < 4) + return fuse_reply_err(req, ENOENT); + + memset(&arg, 0, sizeof(arg)); + fill_entry(&arg, e); +#ifdef POSIXACLS + return send_reply_ok(req, &arg, (req->f->conn.proto_minor >= 12 + ? sizeof(arg) : FUSE_COMPAT_ENTRY_OUT_SIZE)); +#else + return send_reply_ok(req, &arg, sizeof(arg)); +#endif +} + +int fuse_reply_create(fuse_req_t req, const struct fuse_entry_param *e, + const struct fuse_file_info *f) +{ + struct { + struct fuse_entry_out e; + struct fuse_open_out o; + } arg; + + memset(&arg, 0, sizeof(arg)); + fill_entry(&arg.e, e); +#ifdef POSIXACLS + if (req->f->conn.proto_minor < 12) { + fill_open((struct fuse_open_out*) + ((char*)&arg + FUSE_COMPAT_ENTRY_OUT_SIZE), f); + return send_reply_ok(req, &arg, + FUSE_COMPAT_ENTRY_OUT_SIZE + sizeof(struct fuse_open_out)); + } else { + fill_open(&arg.o, f); + return send_reply_ok(req, &arg, sizeof(arg)); + } +#else + fill_open(&arg.o, f); + return send_reply_ok(req, &arg, sizeof(arg)); +#endif +} + +int fuse_reply_attr(fuse_req_t req, const struct stat *attr, + double attr_timeout) +{ + struct fuse_attr_out arg; + + memset(&arg, 0, sizeof(arg)); + arg.attr_valid = calc_timeout_sec(attr_timeout); + arg.attr_valid_nsec = calc_timeout_nsec(attr_timeout); + convert_stat(attr, &arg.attr); + +#ifdef POSIXACLS + return send_reply_ok(req, &arg, (req->f->conn.proto_minor >= 12 + ? sizeof(arg) : FUSE_COMPAT_FUSE_ATTR_OUT_SIZE)); +#else + return send_reply_ok(req, &arg, sizeof(arg)); +#endif +} + +int fuse_reply_readlink(fuse_req_t req, const char *linkname) +{ + return send_reply_ok(req, linkname, strlen(linkname)); +} + +int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *f) +{ + struct fuse_open_out arg; + + memset(&arg, 0, sizeof(arg)); + fill_open(&arg, f); + return send_reply_ok(req, &arg, sizeof(arg)); +} + +int fuse_reply_write(fuse_req_t req, size_t count) +{ + struct fuse_write_out arg; + + memset(&arg, 0, sizeof(arg)); + arg.size = count; + + return send_reply_ok(req, &arg, sizeof(arg)); +} + +int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size) +{ + return send_reply_ok(req, buf, size); +} + +#if HAVE_SYS_STATVFS_H + +int fuse_reply_statfs(fuse_req_t req, const struct statvfs *stbuf) +{ + struct fuse_statfs_out arg; + size_t size = req->f->conn.proto_minor < 4 ? FUSE_COMPAT_STATFS_SIZE : sizeof(arg); + + memset(&arg, 0, sizeof(arg)); + convert_statfs(stbuf, &arg.st); + + return send_reply_ok(req, &arg, size); +} +#endif + + +int fuse_reply_xattr(fuse_req_t req, size_t count) +{ + struct fuse_getxattr_out arg; + + memset(&arg, 0, sizeof(arg)); + arg.size = count; + + return send_reply_ok(req, &arg, sizeof(arg)); +} + +int fuse_reply_lock(fuse_req_t req, struct flock *lock) +{ + struct fuse_lk_out arg; + + memset(&arg, 0, sizeof(arg)); + arg.lk.type = lock->l_type; + if (lock->l_type != F_UNLCK) { + arg.lk.start = lock->l_start; + if (lock->l_len == 0) + arg.lk.end = OFFSET_MAX; + else + arg.lk.end = lock->l_start + lock->l_len - 1; + } + arg.lk.pid = lock->l_pid; + return send_reply_ok(req, &arg, sizeof(arg)); +} + +int fuse_reply_bmap(fuse_req_t req, uint64_t idx) +{ + struct fuse_bmap_out arg; + + memset(&arg, 0, sizeof(arg)); + arg.block = idx; + + return send_reply_ok(req, &arg, sizeof(arg)); +} + +static void do_lookup(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) +{ + const char *name = (const char *) inarg; + + if (req->f->op.lookup) + req->f->op.lookup(req, nodeid, name); + else + fuse_reply_err(req, ENOSYS); +} + +static void do_forget(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) +{ + const struct fuse_forget_in *arg = (const struct fuse_forget_in *) inarg; + + if (req->f->op.forget) + req->f->op.forget(req, nodeid, arg->nlookup); + else + fuse_reply_none(req); +} + +static void do_getattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) +{ + (void) inarg; + + if (req->f->op.getattr) + req->f->op.getattr(req, nodeid, NULL); + else + fuse_reply_err(req, ENOSYS); +} + +static void do_setattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) +{ + const struct fuse_setattr_in *arg = (const struct fuse_setattr_in *) inarg; + + if (req->f->op.setattr) { + struct fuse_file_info *fi = NULL; + struct fuse_file_info fi_store; + struct stat stbuf; + memset(&stbuf, 0, sizeof(stbuf)); + convert_attr(arg, &stbuf); + if (arg->valid & FATTR_FH) { + memset(&fi_store, 0, sizeof(fi_store)); + fi = &fi_store; + fi->fh = arg->fh; + fi->fh_old = fi->fh; + } + req->f->op.setattr(req, nodeid, &stbuf, arg->valid & ~FATTR_FH, fi); + } else + fuse_reply_err(req, ENOSYS); +} + +static void do_access(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) +{ + const struct fuse_access_in *arg = (const struct fuse_access_in *) inarg; + + if (req->f->op.access) + req->f->op.access(req, nodeid, arg->mask); + else + fuse_reply_err(req, ENOSYS); +} + +static void do_readlink(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) +{ + (void) inarg; + + if (req->f->op.readlink) + req->f->op.readlink(req, nodeid); + else + fuse_reply_err(req, ENOSYS); +} + +static void do_mknod(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) +{ + const struct fuse_mknod_in *arg = (const struct fuse_mknod_in *) inarg; + const char *name = PARAM(arg); + +#ifdef POSIXACLS + if (req->f->conn.proto_minor >= 12) + req->ctx.umask = arg->umask; + else +#endif + name = (const char *) inarg + FUSE_COMPAT_MKNOD_IN_SIZE; + + if (req->f->op.mknod) + req->f->op.mknod(req, nodeid, name, arg->mode, arg->rdev); + else + fuse_reply_err(req, ENOSYS); +} + +static void do_mkdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) +{ + const struct fuse_mkdir_in *arg = (const struct fuse_mkdir_in *) inarg; + +#ifdef POSIXACLS + if (req->f->conn.proto_minor >= 12) + req->ctx.umask = arg->umask; +#endif + + if (req->f->op.mkdir) + req->f->op.mkdir(req, nodeid, PARAM(arg), arg->mode); + else + fuse_reply_err(req, ENOSYS); +} + +static void do_unlink(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) +{ + const char *name = (const char *) inarg; + + if (req->f->op.unlink) + req->f->op.unlink(req, nodeid, name); + else + fuse_reply_err(req, ENOSYS); +} + +static void do_rmdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) +{ + const char *name = (const char *) inarg; + + if (req->f->op.rmdir) + req->f->op.rmdir(req, nodeid, name); + else + fuse_reply_err(req, ENOSYS); +} + +static void do_symlink(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) +{ + const char *name = (const char *) inarg; + const char *linkname = ((const char *) inarg) + strlen((const char *) inarg) + 1; + + if (req->f->op.symlink) + req->f->op.symlink(req, linkname, nodeid, name); + else + fuse_reply_err(req, ENOSYS); +} + +static void do_rename(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) +{ + const struct fuse_rename_in *arg = (const struct fuse_rename_in *) inarg; + const char *oldname = PARAM(arg); + const char *newname = oldname + strlen(oldname) + 1; + + if (req->f->op.rename) + req->f->op.rename(req, nodeid, oldname, arg->newdir, newname); + else + fuse_reply_err(req, ENOSYS); +} + +static void do_link(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) +{ + const struct fuse_link_in *arg = (const struct fuse_link_in *) inarg; + + if (req->f->op.link) + req->f->op.link(req, arg->oldnodeid, nodeid, PARAM(arg)); + else + fuse_reply_err(req, ENOSYS); +} + +static void do_create(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) +{ + const struct fuse_create_in *arg = (const struct fuse_create_in *) inarg; + + if (req->f->op.create) { + struct fuse_file_info fi; + const char *name = PARAM(arg); + + memset(&fi, 0, sizeof(fi)); + fi.flags = arg->flags; + +#ifdef POSIXACLS + if (req->f->conn.proto_minor >= 12) + req->ctx.umask = arg->umask; + else +#endif + name = (const char *) inarg + sizeof(struct fuse_open_in); + + req->f->op.create(req, nodeid, name, arg->mode, &fi); + } else + fuse_reply_err(req, ENOSYS); +} + +static void do_open(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) +{ + const struct fuse_open_in *arg = (const struct fuse_open_in *) inarg; + struct fuse_file_info fi; + + memset(&fi, 0, sizeof(fi)); + fi.flags = arg->flags; + + if (req->f->op.open) + req->f->op.open(req, nodeid, &fi); + else + fuse_reply_open(req, &fi); +} + +static void do_read(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) +{ + const struct fuse_read_in *arg = (const struct fuse_read_in *) inarg; + + if (req->f->op.read) { + struct fuse_file_info fi; + + memset(&fi, 0, sizeof(fi)); + fi.fh = arg->fh; + fi.fh_old = fi.fh; + req->f->op.read(req, nodeid, arg->size, arg->offset, &fi); + } else + fuse_reply_err(req, ENOSYS); +} + +static void do_write(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) +{ + const struct fuse_write_in *arg = (const struct fuse_write_in *) inarg; + struct fuse_file_info fi; + + memset(&fi, 0, sizeof(fi)); + fi.fh = arg->fh; + fi.fh_old = fi.fh; + fi.writepage = arg->write_flags & 1; + + if (req->f->op.write) { +#ifdef POSIXACLS + const char *buf; + + if (req->f->conn.proto_minor >= 12) + buf = PARAM(arg); + else + buf = ((const char*)arg) + FUSE_COMPAT_WRITE_IN_SIZE; + req->f->op.write(req, nodeid, buf, arg->size, arg->offset, &fi); +#else + req->f->op.write(req, nodeid, PARAM(arg), arg->size, arg->offset, &fi); +#endif + } else + fuse_reply_err(req, ENOSYS); +} + +static void do_flush(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) +{ + const struct fuse_flush_in *arg = (const struct fuse_flush_in *) inarg; + struct fuse_file_info fi; + + memset(&fi, 0, sizeof(fi)); + fi.fh = arg->fh; + fi.fh_old = fi.fh; + fi.flush = 1; + if (req->f->conn.proto_minor >= 7) + fi.lock_owner = arg->lock_owner; + + if (req->f->op.flush) + req->f->op.flush(req, nodeid, &fi); + else + fuse_reply_err(req, ENOSYS); +} + +static void do_release(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) +{ + const struct fuse_release_in *arg = (const struct fuse_release_in *) inarg; + struct fuse_file_info fi; + + memset(&fi, 0, sizeof(fi)); + fi.flags = arg->flags; + fi.fh = arg->fh; + fi.fh_old = fi.fh; + if (req->f->conn.proto_minor >= 8) { + fi.flush = (arg->release_flags & FUSE_RELEASE_FLUSH) ? 1 : 0; + fi.lock_owner = arg->lock_owner; + } + + if (req->f->op.release) + req->f->op.release(req, nodeid, &fi); + else + fuse_reply_err(req, 0); +} + +static void do_fsync(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) +{ + const struct fuse_fsync_in *arg = (const struct fuse_fsync_in *) inarg; + struct fuse_file_info fi; + + memset(&fi, 0, sizeof(fi)); + fi.fh = arg->fh; + fi.fh_old = fi.fh; + + if (req->f->op.fsync) + req->f->op.fsync(req, nodeid, arg->fsync_flags & 1, &fi); + else + fuse_reply_err(req, ENOSYS); +} + +static void do_opendir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) +{ + const struct fuse_open_in *arg = (const struct fuse_open_in *) inarg; + struct fuse_file_info fi; + + memset(&fi, 0, sizeof(fi)); + fi.flags = arg->flags; + + if (req->f->op.opendir) + req->f->op.opendir(req, nodeid, &fi); + else + fuse_reply_open(req, &fi); +} + +static void do_readdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) +{ + const struct fuse_read_in *arg = (const struct fuse_read_in *) inarg; + struct fuse_file_info fi; + + memset(&fi, 0, sizeof(fi)); + fi.fh = arg->fh; + fi.fh_old = fi.fh; + + if (req->f->op.readdir) + req->f->op.readdir(req, nodeid, arg->size, arg->offset, &fi); + else + fuse_reply_err(req, ENOSYS); +} + +static void do_releasedir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) +{ + const struct fuse_release_in *arg = (const struct fuse_release_in *) inarg; + struct fuse_file_info fi; + + memset(&fi, 0, sizeof(fi)); + fi.flags = arg->flags; + fi.fh = arg->fh; + fi.fh_old = fi.fh; + + if (req->f->op.releasedir) + req->f->op.releasedir(req, nodeid, &fi); + else + fuse_reply_err(req, 0); +} + +static void do_fsyncdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) +{ + const struct fuse_fsync_in *arg = (const struct fuse_fsync_in *) inarg; + struct fuse_file_info fi; + + memset(&fi, 0, sizeof(fi)); + fi.fh = arg->fh; + fi.fh_old = fi.fh; + + if (req->f->op.fsyncdir) + req->f->op.fsyncdir(req, nodeid, arg->fsync_flags & 1, &fi); + else + fuse_reply_err(req, ENOSYS); +} + +static void do_statfs(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) +{ + (void) nodeid; + (void) inarg; + + if (req->f->op.statfs) + req->f->op.statfs(req, nodeid); + else { +#if HAVE_SYS_STATVFS_H + struct statvfs buf = { + .f_namemax = 255, + .f_bsize = 512, + }; + fuse_reply_statfs(req, &buf); +#endif + } +} + +static void do_setxattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) +{ + const struct fuse_setxattr_in *arg = (const struct fuse_setxattr_in *) inarg; + const char *name = PARAM(arg); + const char *value = name + strlen(name) + 1; + + if (req->f->op.setxattr) + req->f->op.setxattr(req, nodeid, name, value, arg->size, arg->flags); + else + fuse_reply_err(req, ENOSYS); +} + +static void do_getxattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) +{ + const struct fuse_getxattr_in *arg = (const struct fuse_getxattr_in *) inarg; + + if (req->f->op.getxattr) + req->f->op.getxattr(req, nodeid, PARAM(arg), arg->size); + else + fuse_reply_err(req, ENOSYS); +} + +static void do_listxattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) +{ + const struct fuse_getxattr_in *arg = (const struct fuse_getxattr_in *) inarg; + + if (req->f->op.listxattr) + req->f->op.listxattr(req, nodeid, arg->size); + else + fuse_reply_err(req, ENOSYS); +} + +static void do_removexattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) +{ + const char *name = (const char *) inarg; + + if (req->f->op.removexattr) + req->f->op.removexattr(req, nodeid, name); + else + fuse_reply_err(req, ENOSYS); +} + +static void convert_fuse_file_lock(const struct fuse_file_lock *fl, + struct flock *flock) +{ + memset(flock, 0, sizeof(struct flock)); + flock->l_type = fl->type; + flock->l_whence = SEEK_SET; + flock->l_start = fl->start; + if (fl->end == OFFSET_MAX) + flock->l_len = 0; + else + flock->l_len = fl->end - fl->start + 1; + flock->l_pid = fl->pid; +} + +static void do_getlk(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) +{ + const struct fuse_lk_in *arg = (const struct fuse_lk_in *) inarg; + struct fuse_file_info fi; + struct flock flock; + + memset(&fi, 0, sizeof(fi)); + fi.fh = arg->fh; + fi.lock_owner = arg->owner; + + convert_fuse_file_lock(&arg->lk, &flock); + if (req->f->op.getlk) + req->f->op.getlk(req, nodeid, &fi, &flock); + else + fuse_reply_err(req, ENOSYS); +} + +static void do_setlk_common(fuse_req_t req, fuse_ino_t nodeid, + const void *inarg, int should_sleep) +{ + const struct fuse_lk_in *arg = (const struct fuse_lk_in *) inarg; + struct fuse_file_info fi; + struct flock flock; + + memset(&fi, 0, sizeof(fi)); + fi.fh = arg->fh; + fi.lock_owner = arg->owner; + + convert_fuse_file_lock(&arg->lk, &flock); + if (req->f->op.setlk) + req->f->op.setlk(req, nodeid, &fi, &flock, should_sleep); + else + fuse_reply_err(req, ENOSYS); +} + +static void do_setlk(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) +{ + do_setlk_common(req, nodeid, inarg, 0); +} + +static void do_setlkw(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) +{ + do_setlk_common(req, nodeid, inarg, 1); +} + +static int find_interrupted(struct fuse_ll *f, struct fuse_req *req) +{ + struct fuse_req *curr; + + for (curr = f->list.next; curr != &f->list; curr = curr->next) { + if (curr->unique == req->u.i.unique) { + curr->ctr++; + pthread_mutex_unlock(&f->lock); + + /* Ugh, ugly locking */ + pthread_mutex_lock(&curr->lock); + pthread_mutex_lock(&f->lock); + curr->interrupted = 1; + pthread_mutex_unlock(&f->lock); + if (curr->u.ni.func) + curr->u.ni.func(curr, curr->u.ni.data); + pthread_mutex_unlock(&curr->lock); + + pthread_mutex_lock(&f->lock); + curr->ctr--; + if (!curr->ctr) + destroy_req(curr); + + return 1; + } + } + for (curr = f->interrupts.next; curr != &f->interrupts; + curr = curr->next) { + if (curr->u.i.unique == req->u.i.unique) + return 1; + } + return 0; +} + +static void do_interrupt(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) +{ + const struct fuse_interrupt_in *arg = (const struct fuse_interrupt_in *) inarg; + struct fuse_ll *f = req->f; + + (void) nodeid; + if (f->debug) + fprintf(stderr, "INTERRUPT: %llu\n", (unsigned long long) arg->unique); + + req->u.i.unique = arg->unique; + + pthread_mutex_lock(&f->lock); + if (find_interrupted(f, req)) + destroy_req(req); + else + list_add_req(req, &f->interrupts); + pthread_mutex_unlock(&f->lock); +} + +static struct fuse_req *check_interrupt(struct fuse_ll *f, struct fuse_req *req) +{ + struct fuse_req *curr; + + for (curr = f->interrupts.next; curr != &f->interrupts; curr = curr->next) { + if (curr->u.i.unique == req->unique) { + req->interrupted = 1; + list_del_req(curr); + free(curr); + return NULL; + } + } + curr = f->interrupts.next; + if (curr != &f->interrupts) { + list_del_req(curr); + list_init_req(curr); + return curr; + } else + return NULL; +} + +static void do_bmap(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) +{ + const struct fuse_bmap_in *arg = (const struct fuse_bmap_in *) inarg; + + if (req->f->op.bmap) + req->f->op.bmap(req, nodeid, arg->blocksize, arg->block); + else + fuse_reply_err(req, ENOSYS); +} + +static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) +{ + const struct fuse_init_in *arg = (const struct fuse_init_in *) inarg; + struct fuse_init_out outarg; + struct fuse_ll *f = req->f; + size_t bufsize = fuse_chan_bufsize(req->ch); + + (void) nodeid; + if (f->debug) { + fprintf(stderr, "INIT: %u.%u\n", arg->major, arg->minor); + if (arg->major > 7 || (arg->major == 7 && arg->minor >= 6)) { + fprintf(stderr, "flags=0x%08x\n", arg->flags); + fprintf(stderr, "max_readahead=0x%08x\n", arg->max_readahead); + } + } + f->conn.proto_major = arg->major; + f->conn.proto_minor = arg->minor; + + if (arg->major < 7) { + fprintf(stderr, "fuse: unsupported protocol version: %u.%u\n", + arg->major, arg->minor); + fuse_reply_err(req, EPROTO); + return; + } + + if (arg->major > 7 || (arg->major == 7 && arg->minor >= 6)) { + if (f->conn.async_read) + f->conn.async_read = arg->flags & FUSE_ASYNC_READ; + if (arg->max_readahead < f->conn.max_readahead) + f->conn.max_readahead = arg->max_readahead; +#ifdef POSIXACLS + if (arg->flags & FUSE_DONT_MASK) + f->conn.capable |= FUSE_CAP_DONT_MASK; +#endif + } else { + f->conn.async_read = 0; + f->conn.max_readahead = 0; + } + + if (bufsize < FUSE_MIN_READ_BUFFER) { + fprintf(stderr, "fuse: warning: buffer size too small: %zu\n", + bufsize); + bufsize = FUSE_MIN_READ_BUFFER; + } + + bufsize -= 4096; + if (bufsize < f->conn.max_write) + f->conn.max_write = bufsize; + + f->got_init = 1; + if (f->op.init) + f->op.init(f->userdata, &f->conn); + + memset(&outarg, 0, sizeof(outarg)); + outarg.major = FUSE_KERNEL_VERSION; + /* + * if POSIXACLS is not set, protocol 7.8 provides a good + * compatibility with older kernel modules. + * if POSIXACLS is set, we try to use protocol 7.12 supposed + * to have the ability to process the umask conditionnally, + * but, when using an older kernel module, we fallback to 7.8 + */ +#ifdef POSIXACLS + if (arg->major > 7 || (arg->major == 7 && arg->minor >= 12)) + outarg.minor = FUSE_KERNEL_MINOR_VERSION; + else + outarg.minor = FUSE_KERNEL_MINOR_FALLBACK; +#else + outarg.minor = FUSE_KERNEL_MINOR_VERSION; +#endif + if (f->conn.async_read) + outarg.flags |= FUSE_ASYNC_READ; + if (f->op.getlk && f->op.setlk) + outarg.flags |= FUSE_POSIX_LOCKS; +#ifdef POSIXACLS + if (f->conn.want & FUSE_CAP_DONT_MASK) + outarg.flags |= FUSE_DONT_MASK; +#endif + outarg.flags |= FUSE_BIG_WRITES ; + outarg.max_readahead = f->conn.max_readahead; + outarg.max_write = f->conn.max_write; + + if (f->debug) { + fprintf(stderr, " INIT: %u.%u\n", outarg.major, outarg.minor); + fprintf(stderr, " flags=0x%08x\n", outarg.flags); + fprintf(stderr, " max_readahead=0x%08x\n", outarg.max_readahead); + fprintf(stderr, " max_write=0x%08x\n", outarg.max_write); + } + + send_reply_ok(req, &outarg, arg->minor < 5 ? 8 : sizeof(outarg)); +} + +static void do_destroy(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) +{ + struct fuse_ll *f = req->f; + + (void) nodeid; + (void) inarg; + + f->got_destroy = 1; + if (f->op.destroy) + f->op.destroy(f->userdata); + + send_reply_ok(req, NULL, 0); +} + +void *fuse_req_userdata(fuse_req_t req) +{ + return req->f->userdata; +} + +const struct fuse_ctx *fuse_req_ctx(fuse_req_t req) +{ + return &req->ctx; +} + +/* + * The size of fuse_ctx got extended, so need to be careful about + * incompatibility (i.e. a new binary cannot work with an old + * library). + */ +const struct fuse_ctx *fuse_req_ctx_compat24(fuse_req_t req); +const struct fuse_ctx *fuse_req_ctx_compat24(fuse_req_t req) +{ + return fuse_req_ctx(req); +} +//FUSE_SYMVER(".symver fuse_req_ctx_compat24,fuse_req_ctx@FUSE_2.4"); + +void fuse_req_interrupt_func(fuse_req_t req, fuse_interrupt_func_t func, + void *data) +{ + pthread_mutex_lock(&req->lock); + req->u.ni.func = func; + req->u.ni.data = data; + if (req->interrupted && func) + func(req, data); + pthread_mutex_unlock(&req->lock); +} + +int fuse_req_interrupted(fuse_req_t req) +{ + int interrupted; + + pthread_mutex_lock(&req->f->lock); + interrupted = req->interrupted; + pthread_mutex_unlock(&req->f->lock); + + return interrupted; +} + +static struct { + void (*func)(fuse_req_t, fuse_ino_t, const void *); + const char *name; +} fuse_ll_ops[] = { + [FUSE_LOOKUP] = { do_lookup, "LOOKUP" }, + [FUSE_FORGET] = { do_forget, "FORGET" }, + [FUSE_GETATTR] = { do_getattr, "GETATTR" }, + [FUSE_SETATTR] = { do_setattr, "SETATTR" }, + [FUSE_READLINK] = { do_readlink, "READLINK" }, + [FUSE_SYMLINK] = { do_symlink, "SYMLINK" }, + [FUSE_MKNOD] = { do_mknod, "MKNOD" }, + [FUSE_MKDIR] = { do_mkdir, "MKDIR" }, + [FUSE_UNLINK] = { do_unlink, "UNLINK" }, + [FUSE_RMDIR] = { do_rmdir, "RMDIR" }, + [FUSE_RENAME] = { do_rename, "RENAME" }, + [FUSE_LINK] = { do_link, "LINK" }, + [FUSE_OPEN] = { do_open, "OPEN" }, + [FUSE_READ] = { do_read, "READ" }, + [FUSE_WRITE] = { do_write, "WRITE" }, + [FUSE_STATFS] = { do_statfs, "STATFS" }, + [FUSE_RELEASE] = { do_release, "RELEASE" }, + [FUSE_FSYNC] = { do_fsync, "FSYNC" }, + [FUSE_SETXATTR] = { do_setxattr, "SETXATTR" }, + [FUSE_GETXATTR] = { do_getxattr, "GETXATTR" }, + [FUSE_LISTXATTR] = { do_listxattr, "LISTXATTR" }, + [FUSE_REMOVEXATTR] = { do_removexattr, "REMOVEXATTR" }, + [FUSE_FLUSH] = { do_flush, "FLUSH" }, + [FUSE_INIT] = { do_init, "INIT" }, + [FUSE_OPENDIR] = { do_opendir, "OPENDIR" }, + [FUSE_READDIR] = { do_readdir, "READDIR" }, + [FUSE_RELEASEDIR] = { do_releasedir, "RELEASEDIR" }, + [FUSE_FSYNCDIR] = { do_fsyncdir, "FSYNCDIR" }, + [FUSE_GETLK] = { do_getlk, "GETLK" }, + [FUSE_SETLK] = { do_setlk, "SETLK" }, + [FUSE_SETLKW] = { do_setlkw, "SETLKW" }, + [FUSE_ACCESS] = { do_access, "ACCESS" }, + [FUSE_CREATE] = { do_create, "CREATE" }, + [FUSE_INTERRUPT] = { do_interrupt, "INTERRUPT" }, + [FUSE_BMAP] = { do_bmap, "BMAP" }, + [FUSE_DESTROY] = { do_destroy, "DESTROY" }, +}; + +#define FUSE_MAXOP (sizeof(fuse_ll_ops) / sizeof(fuse_ll_ops[0])) + +static const char *opname(enum fuse_opcode opcode) +{ + if (opcode >= FUSE_MAXOP || !fuse_ll_ops[opcode].name) + return "???"; + else + return fuse_ll_ops[opcode].name; +} + +static void fuse_ll_process(void *data, const char *buf, size_t len, + struct fuse_chan *ch) +{ + struct fuse_ll *f = (struct fuse_ll *) data; + const struct fuse_in_header *in = (const struct fuse_in_header *) buf; + const void *inarg = buf + sizeof(struct fuse_in_header); + struct fuse_req *req; + + if (f->debug) + fprintf(stderr, "unique: %llu, opcode: %s (%i), nodeid: %lu, insize: %zu\n", + (unsigned long long) in->unique, + opname((enum fuse_opcode) in->opcode), in->opcode, + (unsigned long) in->nodeid, len); + + req = (struct fuse_req *) calloc(1, sizeof(struct fuse_req)); + if (req == NULL) { + fprintf(stderr, "fuse: failed to allocate request\n"); + return; + } + + req->f = f; + req->unique = in->unique; + req->ctx.uid = in->uid; + req->ctx.gid = in->gid; + req->ctx.pid = in->pid; + req->ch = ch; + req->ctr = 1; + list_init_req(req); + fuse_mutex_init(&req->lock); + + if (!f->got_init && in->opcode != FUSE_INIT) + fuse_reply_err(req, EIO); + else if (f->allow_root && in->uid != f->owner && in->uid != 0 && + in->opcode != FUSE_INIT && in->opcode != FUSE_READ && + in->opcode != FUSE_WRITE && in->opcode != FUSE_FSYNC && + in->opcode != FUSE_RELEASE && in->opcode != FUSE_READDIR && + in->opcode != FUSE_FSYNCDIR && in->opcode != FUSE_RELEASEDIR) { + fuse_reply_err(req, EACCES); + } else if (in->opcode >= FUSE_MAXOP || !fuse_ll_ops[in->opcode].func) + fuse_reply_err(req, ENOSYS); + else { + if (in->opcode != FUSE_INTERRUPT) { + struct fuse_req *intr; + pthread_mutex_lock(&f->lock); + intr = check_interrupt(f, req); + list_add_req(req, &f->list); + pthread_mutex_unlock(&f->lock); + if (intr) + fuse_reply_err(intr, EAGAIN); + } + fuse_ll_ops[in->opcode].func(req, in->nodeid, inarg); + } +} + +enum { + KEY_HELP, + KEY_VERSION, +}; + +static struct fuse_opt fuse_ll_opts[] = { + { "debug", offsetof(struct fuse_ll, debug), 1 }, + { "-d", offsetof(struct fuse_ll, debug), 1 }, + { "allow_root", offsetof(struct fuse_ll, allow_root), 1 }, + { "max_write=%u", offsetof(struct fuse_ll, conn.max_write), 0 }, + { "max_readahead=%u", offsetof(struct fuse_ll, conn.max_readahead), 0 }, + { "async_read", offsetof(struct fuse_ll, conn.async_read), 1 }, + { "sync_read", offsetof(struct fuse_ll, conn.async_read), 0 }, + FUSE_OPT_KEY("max_read=", FUSE_OPT_KEY_DISCARD), + FUSE_OPT_KEY("-h", KEY_HELP), + FUSE_OPT_KEY("--help", KEY_HELP), + FUSE_OPT_KEY("-V", KEY_VERSION), + FUSE_OPT_KEY("--version", KEY_VERSION), + FUSE_OPT_END +}; + +static void fuse_ll_version(void) +{ + fprintf(stderr, "using FUSE kernel interface version %i.%i\n", + FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION); +} + +static void fuse_ll_help(void) +{ + fprintf(stderr, +" -o max_write=N set maximum size of write requests\n" +" -o max_readahead=N set maximum readahead\n" +" -o async_read perform reads asynchronously (default)\n" +" -o sync_read perform reads synchronously\n"); +} + +static int fuse_ll_opt_proc(void *data, const char *arg, int key, + struct fuse_args *outargs) +{ + (void) data; (void) outargs; + + switch (key) { + case KEY_HELP: + fuse_ll_help(); + break; + + case KEY_VERSION: + fuse_ll_version(); + break; + + default: + fprintf(stderr, "fuse: unknown option `%s'\n", arg); + } + + return -1; +} + +static void fuse_ll_destroy(void *data) +{ + struct fuse_ll *f = (struct fuse_ll *) data; + + if (f->got_init && !f->got_destroy) { + if (f->op.destroy) + f->op.destroy(f->userdata); + } + + pthread_mutex_destroy(&f->lock); + free(f); +} + +struct fuse_session *fuse_lowlevel_new(struct fuse_args *args, + const struct fuse_lowlevel_ops *op, + size_t op_size, void *userdata) +{ + struct fuse_ll *f; + struct fuse_session *se; + struct fuse_session_ops sop = { + .process = fuse_ll_process, + .destroy = fuse_ll_destroy, + }; + + if (sizeof(struct fuse_lowlevel_ops) < op_size) { + fprintf(stderr, "fuse: warning: library too old, some operations may not work\n"); + op_size = sizeof(struct fuse_lowlevel_ops); + } + + f = (struct fuse_ll *) calloc(1, sizeof(struct fuse_ll)); + if (f == NULL) { + fprintf(stderr, "fuse: failed to allocate fuse object\n"); + goto out; + } + + f->conn.async_read = 1; + f->conn.max_write = UINT_MAX; + f->conn.max_readahead = UINT_MAX; + list_init_req(&f->list); + list_init_req(&f->interrupts); + fuse_mutex_init(&f->lock); + + if (fuse_opt_parse(args, f, fuse_ll_opts, fuse_ll_opt_proc) == -1) + goto out_free; + + memcpy(&f->op, op, op_size); + f->owner = getuid(); + f->userdata = userdata; + + se = fuse_session_new(&sop, f); + if (!se) + goto out_free; + + return se; + + out_free: + free(f); + out: + return NULL; +} + diff --git a/libfuse-lite/fuse_misc.h b/libfuse-lite/fuse_misc.h new file mode 100755 index 0000000..5f02165 --- a/dev/null +++ b/libfuse-lite/fuse_misc.h @@ -0,0 +1,106 @@ +/* + FUSE: Filesystem in Userspace + Copyright (C) 2001-2007 Miklos Szeredi + + This program can be distributed under the terms of the GNU LGPLv2. + See the file COPYING.LIB +*/ + +#include "config.h" +#include + +#ifndef USE_UCLIBC +#define fuse_mutex_init(mut) pthread_mutex_init(mut, NULL) +#else +static inline void fuse_mutex_init(pthread_mutex_t *mut) +{ + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ADAPTIVE_NP); + pthread_mutex_init(mut, &attr); + pthread_mutexattr_destroy(&attr); +} +#endif + +typedef struct _pthread_rwlock_t +{ +// struct _pthread_fastlock __rw_lock; /* Lock to guarantee mutual exclusion */ + int __rw_readers; /* Number of readers */ +// _pthread_descr __rw_writer; /* Identity of writer, or NULL if none */ +// _pthread_descr __rw_read_waiting; /* Threads waiting for reading */ +// _pthread_descr __rw_write_waiting; /* Threads waiting for writing */ + int __rw_kind; /* Reader/Writer preference selection */ + int __rw_pshared; /* Shared between processes or not */ +} pthread_rwlock_t; + +typedef struct +{ + int __lockkind; + int __pshared; +} pthread_rwlockattr_t; + + +static inline int pthread_rwlock_init (pthread_rwlock_t * __rwlock, + pthread_rwlockattr_t *__attr) +{ + return 1; +} + +static inline int pthread_rwlock_destroy (pthread_rwlock_t *__rwlock) +{ + return 1; +} + + + +/* Acquire read lock for RWLOCK. */ +static inline int pthread_rwlock_rdlock (pthread_rwlock_t *__rwlock) +{ + return 1; +} + + +/* Acquire write lock for RWLOCK. */ +static inline int pthread_rwlock_wrlock (pthread_rwlock_t *__rwlock) +{ + return 1; +} + + + + +/* Unlock RWLOCK. */ +static inline int pthread_rwlock_unlock (pthread_rwlock_t *__rwlock) +{ + return 1; +} + + + +#ifdef HAVE_STRUCT_STAT_ST_ATIM +/* Linux */ +#define ST_ATIM_NSEC(stbuf) ((stbuf)->st_atim.tv_nsec) +#define ST_CTIM_NSEC(stbuf) ((stbuf)->st_ctim.tv_nsec) +#define ST_MTIM_NSEC(stbuf) ((stbuf)->st_mtim.tv_nsec) +#define ST_ATIM_NSEC_SET(stbuf, val) (stbuf)->st_atim.tv_nsec = (val) +#define ST_MTIM_NSEC_SET(stbuf, val) (stbuf)->st_mtim.tv_nsec = (val) +#elif defined(HAVE_STRUCT_STAT_ST_ATIMESPEC) +/* FreeBSD */ +#define ST_ATIM_NSEC(stbuf) ((stbuf)->st_atimespec.tv_nsec) +#define ST_CTIM_NSEC(stbuf) ((stbuf)->st_ctimespec.tv_nsec) +#define ST_MTIM_NSEC(stbuf) ((stbuf)->st_mtimespec.tv_nsec) +#define ST_ATIM_NSEC_SET(stbuf, val) (stbuf)->st_atimespec.tv_nsec = (val) +#define ST_MTIM_NSEC_SET(stbuf, val) (stbuf)->st_mtimespec.tv_nsec = (val) +#elif defined(HAVE_STRUCT_STAT_ST_ATIMENSEC) +#define ST_ATIM_NSEC(stbuf) ((stbuf)->st_atimensec) +#define ST_CTIM_NSEC(stbuf) ((stbuf)->st_ctimensec) +#define ST_MTIM_NSEC(stbuf) ((stbuf)->st_mtimensec) +#define ST_ATIM_NSEC_SET(stbuf, val) (stbuf)->st_atimensec = (val) +#define ST_MTIM_NSEC_SET(stbuf, val) (stbuf)->st_mtimensec = (val) +#else +#define ST_ATIM_NSEC(stbuf) 0 +#define ST_CTIM_NSEC(stbuf) 0 +#define ST_MTIM_NSEC(stbuf) 0 +#define ST_ATIM_NSEC_SET(stbuf, val) do { } while (0) +#define ST_MTIM_NSEC_SET(stbuf, val) do { } while (0) +#endif diff --git a/libfuse-lite/fuse_opt.c b/libfuse-lite/fuse_opt.c new file mode 100755 index 0000000..7d76e02 --- a/dev/null +++ b/libfuse-lite/fuse_opt.c @@ -0,0 +1,368 @@ +/* + FUSE: Filesystem in Userspace + Copyright (C) 2001-2007 Miklos Szeredi + + This program can be distributed under the terms of the GNU LGPLv2. + See the file COPYING.LIB +*/ + +#include "config.h" +#include "fuse_opt.h" + +#include +#include +#include +#include + +struct fuse_opt_context { + void *data; + const struct fuse_opt *opt; + fuse_opt_proc_t proc; + int argctr; + int argc; + char **argv; + struct fuse_args outargs; + char *opts; + int nonopt; +}; + +void fuse_opt_free_args(struct fuse_args *args) +{ + if (args) { + if (args->argv && args->allocated) { + int i; + for (i = 0; i < args->argc; i++) + free(args->argv[i]); + free(args->argv); + } + args->argc = 0; + args->argv = NULL; + args->allocated = 0; + } +} + +static int alloc_failed(void) +{ + fprintf(stderr, "fuse: memory allocation failed\n"); + return -1; +} + +int fuse_opt_add_arg(struct fuse_args *args, const char *arg) +{ + char **newargv; + char *newarg; + + assert(!args->argv || args->allocated); + + newargv = realloc(args->argv, (args->argc + 2) * sizeof(char *)); + newarg = newargv ? strdup(arg) : NULL; + if (!newargv || !newarg) + return alloc_failed(); + + args->argv = newargv; + args->allocated = 1; + args->argv[args->argc++] = newarg; + args->argv[args->argc] = NULL; + return 0; +} + +int fuse_opt_insert_arg(struct fuse_args *args, int pos, const char *arg) +{ + assert(pos <= args->argc); + if (fuse_opt_add_arg(args, arg) == -1) + return -1; + + if (pos != args->argc - 1) { + char *newarg = args->argv[args->argc - 1]; + memmove(&args->argv[pos + 1], &args->argv[pos], + sizeof(char *) * (args->argc - pos - 1)); + args->argv[pos] = newarg; + } + return 0; +} + +static int next_arg(struct fuse_opt_context *ctx, const char *opt) +{ + if (ctx->argctr + 1 >= ctx->argc) { + fprintf(stderr, "fuse: missing argument after `%s'\n", opt); + return -1; + } + ctx->argctr++; + return 0; +} + +static int add_arg(struct fuse_opt_context *ctx, const char *arg) +{ + return fuse_opt_add_arg(&ctx->outargs, arg); +} + +int fuse_opt_add_opt(char **opts, const char *opt) +{ + char *newopts; + if (!*opts) + newopts = strdup(opt); + else { + unsigned oldlen = strlen(*opts); + newopts = realloc(*opts, oldlen + 1 + strlen(opt) + 1); + if (newopts) { + newopts[oldlen] = ','; + strcpy(newopts + oldlen + 1, opt); + } + } + if (!newopts) + return alloc_failed(); + + *opts = newopts; + return 0; +} + +static int add_opt(struct fuse_opt_context *ctx, const char *opt) +{ + return fuse_opt_add_opt(&ctx->opts, opt); +} + +static int call_proc(struct fuse_opt_context *ctx, const char *arg, int key, + int iso) +{ + if (key == FUSE_OPT_KEY_DISCARD) + return 0; + + if (key != FUSE_OPT_KEY_KEEP && ctx->proc) { + int res = ctx->proc(ctx->data, arg, key, &ctx->outargs); + if (res == -1 || !res) + return res; + } + if (iso) + return add_opt(ctx, arg); + else + return add_arg(ctx, arg); +} + +static int match_template(const char *t, const char *arg, unsigned *sepp) +{ + int arglen = strlen(arg); + const char *sep = strchr(t, '='); + sep = sep ? sep : strchr(t, ' '); + if (sep && (!sep[1] || sep[1] == '%')) { + int tlen = sep - t; + if (sep[0] == '=') + tlen ++; + if (arglen >= tlen && strncmp(arg, t, tlen) == 0) { + *sepp = sep - t; + return 1; + } + } + if (strcmp(t, arg) == 0) { + *sepp = 0; + return 1; + } + return 0; +} + +static const struct fuse_opt *find_opt(const struct fuse_opt *opt, + const char *arg, unsigned *sepp) +{ + for (; opt && opt->templ; opt++) + if (match_template(opt->templ, arg, sepp)) + return opt; + return NULL; +} + +int fuse_opt_match(const struct fuse_opt *opts, const char *opt) +{ + unsigned dummy; + return find_opt(opts, opt, &dummy) ? 1 : 0; +} + +static int process_opt_param(void *var, const char *format, const char *param, + const char *arg) +{ + assert(format[0] == '%'); + if (format[1] == 's') { + char *copy = strdup(param); + if (!copy) + return alloc_failed(); + + *(char **) var = copy; + } else { + if (sscanf(param, format, var) != 1) { + fprintf(stderr, "fuse: invalid parameter in option `%s'\n", arg); + return -1; + } + } + return 0; +} + +static int process_opt(struct fuse_opt_context *ctx, + const struct fuse_opt *opt, unsigned sep, + const char *arg, int iso) +{ + if (opt->offset == -1U) { + if (call_proc(ctx, arg, opt->value, iso) == -1) + return -1; + } else { + void *var = (char *)ctx->data + opt->offset; + if (sep && opt->templ[sep + 1]) { + const char *param = arg + sep; + if (opt->templ[sep] == '=') + param ++; + if (process_opt_param(var, opt->templ + sep + 1, + param, arg) == -1) + return -1; + } else + *(int *)var = opt->value; + } + return 0; +} + +static int process_opt_sep_arg(struct fuse_opt_context *ctx, + const struct fuse_opt *opt, unsigned sep, + const char *arg, int iso) +{ + int res; + char *newarg; + char *param; + + if (next_arg(ctx, arg) == -1) + return -1; + + param = ctx->argv[ctx->argctr]; + newarg = malloc(sep + strlen(param) + 1); + if (!newarg) + return alloc_failed(); + + memcpy(newarg, arg, sep); + strcpy(newarg + sep, param); + res = process_opt(ctx, opt, sep, newarg, iso); + free(newarg); + + return res; +} + +static int process_gopt(struct fuse_opt_context *ctx, const char *arg, int iso) +{ + unsigned sep; + const struct fuse_opt *opt = find_opt(ctx->opt, arg, &sep); + if (opt) { + for (; opt; opt = find_opt(opt + 1, arg, &sep)) { + int res; + if (sep && opt->templ[sep] == ' ' && !arg[sep]) + res = process_opt_sep_arg(ctx, opt, sep, arg, iso); + else + res = process_opt(ctx, opt, sep, arg, iso); + if (res == -1) + return -1; + } + return 0; + } else + return call_proc(ctx, arg, FUSE_OPT_KEY_OPT, iso); +} + +static int process_real_option_group(struct fuse_opt_context *ctx, char *opts) +{ + char *sep; + + do { + int res; + sep = strchr(opts, ','); + if (sep) + *sep = '\0'; + res = process_gopt(ctx, opts, 1); + if (res == -1) + return -1; + opts = sep + 1; + } while (sep); + + return 0; +} + +static int process_option_group(struct fuse_opt_context *ctx, const char *opts) +{ + int res; + char *copy; + const char *sep = strchr(opts, ','); + if (!sep) + return process_gopt(ctx, opts, 1); + + copy = strdup(opts); + if (!copy) { + fprintf(stderr, "fuse: memory allocation failed\n"); + return -1; + } + res = process_real_option_group(ctx, copy); + free(copy); + return res; +} + +static int process_one(struct fuse_opt_context *ctx, const char *arg) +{ + if (ctx->nonopt || arg[0] != '-') + return call_proc(ctx, arg, FUSE_OPT_KEY_NONOPT, 0); + else if (arg[1] == 'o') { + if (arg[2]) + return process_option_group(ctx, arg + 2); + else { + if (next_arg(ctx, arg) == -1) + return -1; + + return process_option_group(ctx, ctx->argv[ctx->argctr]); + } + } else if (arg[1] == '-' && !arg[2]) { + if (add_arg(ctx, arg) == -1) + return -1; + ctx->nonopt = ctx->outargs.argc; + return 0; + } else + return process_gopt(ctx, arg, 0); +} + +static int opt_parse(struct fuse_opt_context *ctx) +{ + if (ctx->argc) { + if (add_arg(ctx, ctx->argv[0]) == -1) + return -1; + } + + for (ctx->argctr = 1; ctx->argctr < ctx->argc; ctx->argctr++) + if (process_one(ctx, ctx->argv[ctx->argctr]) == -1) + return -1; + + if (ctx->opts) { + if (fuse_opt_insert_arg(&ctx->outargs, 1, "-o") == -1 || + fuse_opt_insert_arg(&ctx->outargs, 2, ctx->opts) == -1) + return -1; + } + if (ctx->nonopt && ctx->nonopt == ctx->outargs.argc) { + free(ctx->outargs.argv[ctx->outargs.argc - 1]); + ctx->outargs.argv[--ctx->outargs.argc] = NULL; + } + + return 0; +} + +int fuse_opt_parse(struct fuse_args *args, void *data, + const struct fuse_opt opts[], fuse_opt_proc_t proc) +{ + int res; + struct fuse_opt_context ctx = { + .data = data, + .opt = opts, + .proc = proc, + }; + + if (!args || !args->argv || !args->argc) + return 0; + + ctx.argc = args->argc; + ctx.argv = args->argv; + + res = opt_parse(&ctx); + if (res != -1) { + struct fuse_args tmp = *args; + *args = ctx.outargs; + ctx.outargs = tmp; + } + free(ctx.opts); + fuse_opt_free_args(&ctx.outargs); + return res; +} diff --git a/libfuse-lite/fuse_session.c b/libfuse-lite/fuse_session.c new file mode 100755 index 0000000..c4e544d --- a/dev/null +++ b/libfuse-lite/fuse_session.c @@ -0,0 +1,183 @@ +/* + FUSE: Filesystem in Userspace + Copyright (C) 2001-2007 Miklos Szeredi + + This program can be distributed under the terms of the GNU LGPLv2. + See the file COPYING.LIB +*/ + +#include "config.h" +#include "fuse_lowlevel.h" +#include "fuse_lowlevel_compat.h" + +#include +#include +#include +#include +#include + +struct fuse_session { + struct fuse_session_ops op; + + void *data; + + volatile int exited; + + struct fuse_chan *ch; +}; + +struct fuse_chan { + struct fuse_chan_ops op; + + struct fuse_session *se; + + int fd; + + size_t bufsize; + + void *data; +}; + +struct fuse_session *fuse_session_new(struct fuse_session_ops *op, void *data) +{ + struct fuse_session *se = (struct fuse_session *) malloc(sizeof(*se)); + if (se == NULL) { + fprintf(stderr, "fuse: failed to allocate session\n"); + return NULL; + } + + memset(se, 0, sizeof(*se)); + se->op = *op; + se->data = data; + + return se; +} + +void fuse_session_add_chan(struct fuse_session *se, struct fuse_chan *ch) +{ + assert(se->ch == NULL); + assert(ch->se == NULL); + se->ch = ch; + ch->se = se; +} + +void fuse_session_remove_chan(struct fuse_chan *ch) +{ + struct fuse_session *se = ch->se; + if (se) { + assert(se->ch == ch); + se->ch = NULL; + ch->se = NULL; + } +} + +struct fuse_chan *fuse_session_next_chan(struct fuse_session *se, + struct fuse_chan *ch) +{ + assert(ch == NULL || ch == se->ch); + if (ch == NULL) + return se->ch; + else + return NULL; +} + +void fuse_session_process(struct fuse_session *se, const char *buf, size_t len, + struct fuse_chan *ch) +{ + se->op.process(se->data, buf, len, ch); +} + +void fuse_session_destroy(struct fuse_session *se) +{ + if (se->op.destroy) + se->op.destroy(se->data); + if (se->ch != NULL) + fuse_chan_destroy(se->ch); + free(se); +} + +void fuse_session_exit(struct fuse_session *se) +{ + if (se->op.exit) + se->op.exit(se->data, 1); + se->exited = 1; +} + +void fuse_session_reset(struct fuse_session *se) +{ + if (se->op.exit) + se->op.exit(se->data, 0); + se->exited = 0; +} + +int fuse_session_exited(struct fuse_session *se) +{ + if (se->op.exited) + return se->op.exited(se->data); + else + return se->exited; +} + +static struct fuse_chan *fuse_chan_new_common(struct fuse_chan_ops *op, int fd, + size_t bufsize, void *data) +{ + struct fuse_chan *ch = (struct fuse_chan *) malloc(sizeof(*ch)); + if (ch == NULL) { + fprintf(stderr, "fuse: failed to allocate channel\n"); + return NULL; + } + + memset(ch, 0, sizeof(*ch)); + ch->op = *op; + ch->fd = fd; + ch->bufsize = bufsize; + ch->data = data; + + return ch; +} + +struct fuse_chan *fuse_chan_new(struct fuse_chan_ops *op, int fd, + size_t bufsize, void *data) +{ + return fuse_chan_new_common(op, fd, bufsize, data); +} + +int fuse_chan_fd(struct fuse_chan *ch) +{ + return ch->fd; +} + +size_t fuse_chan_bufsize(struct fuse_chan *ch) +{ + return ch->bufsize; +} + +void *fuse_chan_data(struct fuse_chan *ch) +{ + return ch->data; +} + +struct fuse_session *fuse_chan_session(struct fuse_chan *ch) +{ + return ch->se; +} + +int fuse_chan_recv(struct fuse_chan **chp, char *buf, size_t size) +{ + struct fuse_chan *ch = *chp; + return ch->op.receive(chp, buf, size); +} + +int fuse_chan_send(struct fuse_chan *ch, const struct iovec iov[], size_t count) +{ + return ch->op.send(ch, iov, count); +} + +void fuse_chan_destroy(struct fuse_chan *ch) +{ + fuse_session_remove_chan(ch); + if (ch->op.destroy) + ch->op.destroy(ch); + free(ch); +} + diff --git a/libfuse-lite/fuse_signals.c b/libfuse-lite/fuse_signals.c new file mode 100755 index 0000000..bf97956 --- a/dev/null +++ b/libfuse-lite/fuse_signals.c @@ -0,0 +1,73 @@ +/* + FUSE: Filesystem in Userspace + Copyright (C) 2001-2007 Miklos Szeredi + + This program can be distributed under the terms of the GNU LGPLv2. + See the file COPYING.LIB +*/ + +#include "config.h" +#include "fuse_lowlevel.h" + +#include +#include +#include + +static struct fuse_session *fuse_instance; + +static void exit_handler(int sig) +{ + (void) sig; + if (fuse_instance) + fuse_session_exit(fuse_instance); +} + +static int set_one_signal_handler(int sig, void (*handler)(int)) +{ + struct sigaction sa; + struct sigaction old_sa; + + memset(&sa, 0, sizeof(struct sigaction)); + sa.sa_handler = handler; + sigemptyset(&(sa.sa_mask)); + sa.sa_flags = 0; + + if (sigaction(sig, NULL, &old_sa) == -1) { + perror("fuse: cannot get old signal handler"); + return -1; + } + + if (old_sa.sa_handler == SIG_DFL && + sigaction(sig, &sa, NULL) == -1) { + perror("fuse: cannot set signal handler"); + return -1; + } + return 0; +} + +int fuse_set_signal_handlers(struct fuse_session *se) +{ + if (set_one_signal_handler(SIGHUP, exit_handler) == -1 || + set_one_signal_handler(SIGINT, exit_handler) == -1 || + set_one_signal_handler(SIGTERM, exit_handler) == -1 || + set_one_signal_handler(SIGPIPE, SIG_IGN) == -1) + return -1; + + fuse_instance = se; + return 0; +} + +void fuse_remove_signal_handlers(struct fuse_session *se) +{ + if (fuse_instance != se) + fprintf(stderr, + "fuse: fuse_remove_signal_handlers: unknown session\n"); + else + fuse_instance = NULL; + + set_one_signal_handler(SIGHUP, SIG_DFL); + set_one_signal_handler(SIGINT, SIG_DFL); + set_one_signal_handler(SIGTERM, SIG_DFL); + set_one_signal_handler(SIGPIPE, SIG_DFL); +} + diff --git a/libfuse-lite/fusermount.c b/libfuse-lite/fusermount.c new file mode 100755 index 0000000..bfe057b --- a/dev/null +++ b/libfuse-lite/fusermount.c @@ -0,0 +1,772 @@ +/* + FUSE: Filesystem in Userspace + Copyright (C) 2001-2007 Miklos Szeredi + + This program can be distributed under the terms of the GNU GPL. + See the file COPYING. +*/ +/* This program does the mounting and unmounting of FUSE filesystems */ + +#include + +#include "mount_util.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define FUSE_DEV_NEW "/dev/fuse" + +#ifndef MS_DIRSYNC +#define MS_DIRSYNC 128 +#endif + + +struct mntent *getmntent_r (FILE *filep, + struct mntent *mnt, char *buff, int bufsize) +{ + static const char sep[] = " \t\n"; + + char *cp, *ptrptr; + + if (!filep || !mnt || !buff) + return NULL; + + /* Loop on the file, skipping comment lines. - FvK 03/07/93 */ + while ((cp = fgets(buff, bufsize, filep)) != NULL) { + if (buff[0] == '#' || buff[0] == '\n') + continue; + break; + } + + /* At the EOF, the buffer should be unchanged. We should + * check the return value from fgets (). + */ + if (cp == NULL) + return NULL; + + ptrptr = 0; + mnt->mnt_fsname = strtok_r(buff, sep, &ptrptr); + if (mnt->mnt_fsname == NULL) + return NULL; + + mnt->mnt_dir = strtok_r(NULL, sep, &ptrptr); + if (mnt->mnt_dir == NULL) + return NULL; + + mnt->mnt_type = strtok_r(NULL, sep, &ptrptr); + if (mnt->mnt_type == NULL) + return NULL; + + mnt->mnt_opts = strtok_r(NULL, sep, &ptrptr); + if (mnt->mnt_opts == NULL) + mnt->mnt_opts = ""; + + cp = strtok_r(NULL, sep, &ptrptr); + mnt->mnt_freq = (cp != NULL) ? atoi(cp) : 0; + + cp = strtok_r(NULL, sep, &ptrptr); + mnt->mnt_passno = (cp != NULL) ? atoi(cp) : 0; + + return mnt; +} + + +#if 0 +struct mntent *getmntent(FILE * filep) +{ + struct mntent *tmp; + static char *buff = NULL; + static struct mntent mnt; +// __UCLIBC_MUTEX_LOCK(mylock); + + if (!buff) { + buff = malloc(BUFSIZ); + if (!buff) + abort(); + } + + tmp = getmntent_r(filep, &mnt, buff, BUFSIZ); +// __UCLIBC_MUTEX_UNLOCK(mylock); + return(tmp); +} +#endif + +int addmntent(FILE * filep, const struct mntent *mnt) +{ + if (fseek(filep, 0, SEEK_END) < 0) + return 1; + + return (fprintf (filep, "%s %s %s %s %d %d\n", mnt->mnt_fsname, mnt->mnt_dir, + mnt->mnt_type, mnt->mnt_opts, mnt->mnt_freq, mnt->mnt_passno) < 0 ? 1 : 0); +} + +char *hasmntopt(const struct mntent *mnt, const char *opt) +{ + return strstr(mnt->mnt_opts, opt); +} + +FILE *setmntent(const char *name, const char *mode) +{ + return fopen(name, mode); +} + + +int endmntent(FILE * filep) +{ + if (filep != NULL) + fclose(filep); + return 1; +} + + + +static const char *progname = "ntfs-3g-mount"; + +static int mount_max = 1000; + +int drop_privs(void); +int restore_privs(void); + +static const char *get_user_name(void) +{ + struct passwd *pw = getpwuid(getuid()); + if (pw != NULL && pw->pw_name != NULL) + return pw->pw_name; + else { + fprintf(stderr, "%s: could not determine username\n", progname); + return NULL; + } +} + +int drop_privs(void) +{ + if (!getegid()) { + + gid_t new_gid = getgid(); + + if (setresgid(-1, new_gid, getegid()) < 0) { + perror("priv drop: setresgid failed"); + return -1; + } + if (getegid() != new_gid){ + perror("dropping group privilege failed"); + return -1; + } + } + + if (!geteuid()) { + + uid_t new_uid = getuid(); + + if (setresuid(-1, new_uid, geteuid()) < 0) { + perror("priv drop: setresuid failed"); + return -1; + } + if (geteuid() != new_uid){ + perror("dropping user privilege failed"); + return -1; + } + } + + return 0; +} + +int restore_privs(void) +{ + if (geteuid()) { + + uid_t ruid, euid, suid; + + if (getresuid(&ruid, &euid, &suid) < 0) { + perror("priv restore: getresuid failed"); + return -1; + } + if (setresuid(-1, suid, -1) < 0) { + perror("priv restore: setresuid failed"); + return -1; + } + if (geteuid() != suid) { + perror("restoring privilege failed"); + return -1; + } + } + + if (getegid()) { + + gid_t rgid, egid, sgid; + + if (getresgid(&rgid, &egid, &sgid) < 0) { + perror("priv restore: getresgid failed"); + return -1; + } + if (setresgid(-1, sgid, -1) < 0) { + perror("priv restore: setresgid failed"); + return -1; + } + if (getegid() != sgid){ + perror("restoring group privilege failed"); + return -1; + } + } + + return 0; +} + +#ifndef IGNORE_MTAB +static int add_mount(const char *source, const char *mnt, const char *type, + const char *opts) +{ + return fuse_mnt_add_mount(progname, source, mnt, type, opts); +} + + + +static int count_fuse_fs(void) +{ + struct mntent *entp; + int count = 0; + const char *mtab = _PATH_MOUNTED; + FILE *fp = setmntent(mtab, "r"); + if (fp == NULL) { + fprintf(stderr, "%s: failed to open %s: %s\n", progname, mtab, + strerror(errno)); + return -1; + } + while ((entp = getmntent(fp)) != NULL) { + if (strcmp(entp->mnt_type, "fuse") == 0 || + strncmp(entp->mnt_type, "fuse.", 5) == 0) + count ++; + } + endmntent(fp); + return count; +} + + +#else /* IGNORE_MTAB */ +static int count_fuse_fs() +{ + return 0; +} + +static int add_mount(const char *source, const char *mnt, const char *type, + const char *opts) +{ + (void) source; + (void) mnt; + (void) type; + (void) opts; + return 0; +} +#endif /* IGNORE_MTAB */ + +static int begins_with(const char *s, const char *beg) +{ + if (strncmp(s, beg, strlen(beg)) == 0) + return 1; + else + return 0; +} + +struct mount_flags { + const char *opt; + unsigned long flag; + int on; + int safe; +}; + +static struct mount_flags mount_flags[] = { + {"rw", MS_RDONLY, 0, 1}, + {"ro", MS_RDONLY, 1, 1}, + {"suid", MS_NOSUID, 0, 0}, + {"nosuid", MS_NOSUID, 1, 1}, + {"dev", MS_NODEV, 0, 0}, + {"nodev", MS_NODEV, 1, 1}, + {"exec", MS_NOEXEC, 0, 1}, + {"noexec", MS_NOEXEC, 1, 1}, + {"async", MS_SYNCHRONOUS, 0, 1}, + {"sync", MS_SYNCHRONOUS, 1, 1}, + {"atime", MS_NOATIME, 0, 1}, + {"noatime", MS_NOATIME, 1, 1}, + {"dirsync", MS_DIRSYNC, 1, 1}, + {NULL, 0, 0, 0} +}; + +static int find_mount_flag(const char *s, unsigned len, int *on, int *flag) +{ + int i; + + for (i = 0; mount_flags[i].opt != NULL; i++) { + const char *opt = mount_flags[i].opt; + if (strlen(opt) == len && strncmp(opt, s, len) == 0) { + *on = mount_flags[i].on; + *flag = mount_flags[i].flag; + if (!mount_flags[i].safe && getuid() != 0) { + *flag = 0; + fprintf(stderr, "%s: unsafe option '%s' ignored\n", + progname, opt); + } + return 1; + } + } + return 0; +} + +static int add_option(char **optsp, const char *opt, unsigned expand) +{ + char *newopts; + if (*optsp == NULL) + newopts = strdup(opt); + else { + unsigned oldsize = strlen(*optsp); + unsigned newsize = oldsize + 1 + strlen(opt) + expand + 1; + newopts = (char *) realloc(*optsp, newsize); + if (newopts) + sprintf(newopts + oldsize, ",%s", opt); + } + if (newopts == NULL) { + fprintf(stderr, "%s: failed to allocate memory\n", progname); + return -1; + } + *optsp = newopts; + return 0; +} + +static int get_mnt_opts(int flags, char *opts, char **mnt_optsp) +{ + int i; + int l; + + if (!(flags & MS_RDONLY) && add_option(mnt_optsp, "rw", 0) == -1) + return -1; + + for (i = 0; mount_flags[i].opt != NULL; i++) { + if (mount_flags[i].on && (flags & mount_flags[i].flag) && + add_option(mnt_optsp, mount_flags[i].opt, 0) == -1) + return -1; + } + + if (add_option(mnt_optsp, opts, 0) == -1) + return -1; + /* remove comma from end of opts*/ + l = strlen(*mnt_optsp); + if ((*mnt_optsp)[l-1] == ',') + (*mnt_optsp)[l-1] = '\0'; + if (getuid() != 0) { + const char *user = get_user_name(); + if (user == NULL) + return -1; + + if (add_option(mnt_optsp, "user=", strlen(user)) == -1) + return -1; + strcat(*mnt_optsp, user); + } + return 0; +} + +static int opt_eq(const char *s, unsigned len, const char *opt) +{ + if(strlen(opt) == len && strncmp(s, opt, len) == 0) + return 1; + else + return 0; +} + +static int get_string_opt(const char *s, unsigned len, const char *opt, + char **val) +{ + unsigned opt_len = strlen(opt); + + if (*val) + free(*val); + *val = (char *) malloc(len - opt_len + 1); + if (!*val) { + fprintf(stderr, "%s: failed to allocate memory\n", progname); + return 0; + } + + memcpy(*val, s + opt_len, len - opt_len); + (*val)[len - opt_len] = '\0'; + return 1; +} + +static int do_mount(const char *mnt, char **typep, mode_t rootmode, + int fd, const char *opts, const char *dev, char **sourcep, + char **mnt_optsp) +{ + int res; + int flags = MS_NOSUID | MS_NODEV; + char *optbuf; + char *mnt_opts = NULL; + const char *s; + char *d; + char *fsname = NULL; + char *source = NULL; + char *type = NULL; + int blkdev = 0; + + optbuf = (char *) malloc(strlen(opts) + 128); + if (!optbuf) { + fprintf(stderr, "%s: failed to allocate memory\n", progname); + return -1; + } + + for (s = opts, d = optbuf; *s;) { + unsigned len; + const char *fsname_str = "fsname="; + for (len = 0; s[len] && s[len] != ','; len++); + if (begins_with(s, fsname_str)) { + if (!get_string_opt(s, len, fsname_str, &fsname)) + goto err; + } else if (opt_eq(s, len, "blkdev")) { + blkdev = 1; + } else if (!begins_with(s, "fd=") && + !begins_with(s, "rootmode=") && + !begins_with(s, "user_id=") && + !begins_with(s, "group_id=")) { + int on; + int flag; + int skip_option = 0; + if (opt_eq(s, len, "large_read")) { + struct utsname utsname; + unsigned kmaj, kmin; + res = uname(&utsname); + if (res == 0 && + sscanf(utsname.release, "%u.%u", &kmaj, &kmin) == 2 && + (kmaj > 2 || (kmaj == 2 && kmin > 4))) { + fprintf(stderr, "%s: note: 'large_read' mount option is " + "deprecated for %i.%i kernels\n", progname, kmaj, kmin); + skip_option = 1; + } + } + if (!skip_option) { + if (find_mount_flag(s, len, &on, &flag)) { + if (on) + flags |= flag; + else + flags &= ~flag; + } else { + memcpy(d, s, len); + d += len; + *d++ = ','; + } + } + } + s += len; + if (*s) + s++; + } + *d = '\0'; + res = get_mnt_opts(flags, optbuf, &mnt_opts); + if (res == -1) + goto err; + + sprintf(d, "fd=%i,rootmode=%o,user_id=%i,group_id=%i", + fd, rootmode, getuid(), getgid()); + + source = malloc((fsname ? strlen(fsname) : 0) + strlen(dev) + 32); + + type = malloc(32); + if (!type || !source) { + fprintf(stderr, "%s: failed to allocate memory\n", progname); + goto err; + } + + strcpy(type, blkdev ? "fuseblk" : "fuse"); + + if (fsname) + strcpy(source, fsname); + else + strcpy(source, dev); + + if (restore_privs()) + goto err; + + res = mount(source, mnt, type, flags, optbuf); + if (res == -1 && errno == EINVAL) { + /* It could be an old version not supporting group_id */ + sprintf(d, "fd=%i,rootmode=%o,user_id=%i", fd, rootmode, getuid()); + res = mount(source, mnt, type, flags, optbuf); + } + + if (drop_privs()) + goto err; + + if (res == -1) { + int errno_save = errno; + if (blkdev && errno == ENODEV && !fuse_mnt_check_fuseblk()) + fprintf(stderr, "%s: 'fuseblk' support missing\n", progname); + else { + fprintf(stderr, "%s: mount failed: %s\n", progname, strerror(errno_save)); + if (errno_save == EPERM) + fprintf(stderr, "User doesn't have privilege to mount. " + "For more information\nplease see: " + "http://ntfs-3g.org/support.html#unprivileged\n"); + } + goto err; + } else { + *sourcep = source; + *typep = type; + *mnt_optsp = mnt_opts; + } +out: + free(fsname); + free(optbuf); + return res; +err: + free(source); + free(type); + free(mnt_opts); + res = -1; + goto out; +} + +static int check_perm(const char **mntp, struct stat *stbuf, int *currdir_fd, + int *mountpoint_fd) +{ + int res; + const char *mnt = *mntp; + const char *origmnt = mnt; + + res = stat(mnt, stbuf); + if (res == -1) { + fprintf(stderr, "%s: failed to access mountpoint %s: %s\n", + progname, mnt, strerror(errno)); + return -1; + } + + /* No permission checking is done for root */ + if (getuid() == 0) + return 0; + + if (S_ISDIR(stbuf->st_mode)) { + *currdir_fd = open(".", O_RDONLY); + if (*currdir_fd == -1) { + fprintf(stderr, "%s: failed to open current directory: %s\n", + progname, strerror(errno)); + return -1; + } + res = chdir(mnt); + if (res == -1) { + fprintf(stderr, "%s: failed to chdir to mountpoint: %s\n", + progname, strerror(errno)); + return -1; + } + mnt = *mntp = "."; + res = lstat(mnt, stbuf); + if (res == -1) { + fprintf(stderr, "%s: failed to access mountpoint %s: %s\n", + progname, origmnt, strerror(errno)); + return -1; + } + + if ((stbuf->st_mode & S_ISVTX) && stbuf->st_uid != getuid()) { + fprintf(stderr, "%s: mountpoint %s not owned by user\n", + progname, origmnt); + return -1; + } + + res = access(mnt, W_OK); + if (res == -1) { + fprintf(stderr, "%s: user has no write access to mountpoint %s\n", + progname, origmnt); + return -1; + } + } else if (S_ISREG(stbuf->st_mode)) { + static char procfile[256]; + *mountpoint_fd = open(mnt, O_WRONLY); + if (*mountpoint_fd == -1) { + fprintf(stderr, "%s: failed to open %s: %s\n", progname, mnt, + strerror(errno)); + return -1; + } + res = fstat(*mountpoint_fd, stbuf); + if (res == -1) { + fprintf(stderr, "%s: failed to access mountpoint %s: %s\n", + progname, mnt, strerror(errno)); + return -1; + } + if (!S_ISREG(stbuf->st_mode)) { + fprintf(stderr, "%s: mountpoint %s is no longer a regular file\n", + progname, mnt); + return -1; + } + + sprintf(procfile, "/proc/self/fd/%i", *mountpoint_fd); + *mntp = procfile; + } else { + fprintf(stderr, + "%s: mountpoint %s is not a directory or a regular file\n", + progname, mnt); + return -1; + } + + + return 0; +} + +static int try_open(const char *dev, char **devp) +{ + int fd; + + if (restore_privs()) + return -1; + fd = open(dev, O_RDWR); + if (drop_privs()) + return -1; + if (fd != -1) { + *devp = strdup(dev); + if (*devp == NULL) { + fprintf(stderr, "%s: failed to allocate memory\n", progname); + close(fd); + fd = -1; + } + } else if (errno == ENODEV || + errno == ENOENT) /* check for ENOENT too, for the udev case */ + return -2; + else { + fprintf(stderr, "%s: failed to open %s: %s\n", progname, dev, + strerror(errno)); + } + return fd; +} + +static int open_fuse_device(char **devp) +{ + int fd; + + fd = try_open(FUSE_DEV_NEW, devp); + if (fd >= -1) + return fd; + + fprintf(stderr, "%s: fuse device is missing, try 'modprobe fuse' as root\n", + progname); + + return -1; +} + + +static int mount_fuse(const char *mnt, const char *opts) +{ + int res; + int fd; + char *dev; + struct stat stbuf; + char *type = NULL; + char *source = NULL; + char *mnt_opts = NULL; + const char *real_mnt = mnt; + int currdir_fd = -1; + int mountpoint_fd = -1; + + fd = open_fuse_device(&dev); + if (fd == -1) + return -1; + + if (getuid() != 0 && mount_max != -1) { + if (count_fuse_fs() >= mount_max) { + fprintf(stderr, "%s: too many mounted FUSE filesystems (%d+)\n", + progname, mount_max); + goto err; + } + } + + res = check_perm(&real_mnt, &stbuf, &currdir_fd, &mountpoint_fd); + if (res != -1) + res = do_mount(real_mnt, &type, stbuf.st_mode & S_IFMT, fd, opts, dev, + &source, &mnt_opts); + + if (currdir_fd != -1) { + __attribute__((unused))int ignored_fchdir_status = + fchdir(currdir_fd); + close(currdir_fd); + } + if (mountpoint_fd != -1) + close(mountpoint_fd); + + if (res == -1) + goto err; + + if (restore_privs()) + goto err; + + if (geteuid() == 0) { + + if (setgroups(0, NULL) == -1) { + perror("priv drop: setgroups failed"); + goto err; + } + + res = add_mount(source, mnt, type, mnt_opts); + if (res == -1) { + umount2(mnt, 2); /* lazy umount */ + drop_privs(); + goto err; + } + } + + if (drop_privs()) + goto err; +out: + free(source); + free(type); + free(mnt_opts); + free(dev); + + return fd; +err: + close(fd); + fd = -1; + goto out; +} + +int fusermount(int unmount, int quiet, int lazy, const char *opts, + const char *origmnt) +{ + int res = -1; + char *mnt; + mode_t old_umask; + + mnt = fuse_mnt_resolve_path(progname, origmnt); + if (mnt == NULL) + return -1; + + old_umask = umask(033); + + if (unmount) { + + if (restore_privs()) + goto out; + + if (geteuid() == 0) + res = fuse_mnt_umount(progname, mnt, lazy); + else { + res = umount2(mnt, lazy ? 2 : 0); + if (res == -1 && !quiet) + fprintf(stderr, "%s: failed to unmount %s: %s\n", progname, + mnt, strerror(errno)); + } + + if (drop_privs()) + res = -1; + + } else + res = mount_fuse(mnt, opts); +out: + umask(old_umask); + free(mnt); + return res; +} diff --git a/libfuse-lite/helper.c b/libfuse-lite/helper.c new file mode 100755 index 0000000..6c640ae --- a/dev/null +++ b/libfuse-lite/helper.c @@ -0,0 +1,40 @@ +/* + FUSE: Filesystem in Userspace + Copyright (C) 2001-2007 Miklos Szeredi + + This program can be distributed under the terms of the GNU LGPLv2. + See the file COPYING.LIB. +*/ + +#include "config.h" +#include "fuse_i.h" +#include "fuse_lowlevel.h" + +struct fuse_chan *fuse_mount(const char *mountpoint, struct fuse_args *args) +{ + struct fuse_chan *ch; + int fd; + + fd = fuse_kern_mount(mountpoint, args); + if (fd == -1) + return NULL; + + ch = fuse_kern_chan_new(fd); + if (!ch) + fuse_kern_unmount(mountpoint, fd); + + return ch; +} + +void fuse_unmount(const char *mountpoint, struct fuse_chan *ch) +{ + int fd = ch ? fuse_chan_fd(ch) : -1; + fuse_kern_unmount(mountpoint, fd); + fuse_chan_destroy(ch); +} + +int fuse_version(void) +{ + return FUSE_VERSION; +} + diff --git a/libfuse-lite/mount.c b/libfuse-lite/mount.c new file mode 100755 index 0000000..0bb3aee --- a/dev/null +++ b/libfuse-lite/mount.c @@ -0,0 +1,256 @@ +/* + FUSE: Filesystem in Userspace + Copyright (C) 2001-2007 Miklos Szeredi + + This program can be distributed under the terms of the GNU LGPLv2. + See the file COPYING.LIB. +*/ + +#include "config.h" +#include "fuse_i.h" +#include "fuse_opt.h" +#include "mount_util.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef MS_DIRSYNC +#define MS_DIRSYNC 128 +#endif + +enum { + KEY_KERN_FLAG, + KEY_KERN_OPT, + KEY_FUSERMOUNT_OPT, + KEY_SUBTYPE_OPT, + KEY_MTAB_OPT, + KEY_ALLOW_ROOT, + KEY_RO, + KEY_HELP, + KEY_VERSION, +}; + +struct mount_opts { + int allow_other; + int allow_root; + int ishelp; + int flags; + int blkdev; + char *fsname; + char *mtab_opts; + char *fusermount_opts; + char *kernel_opts; +}; + +#define FUSE_MOUNT_OPT(t, p) { t, offsetof(struct mount_opts, p), 1 } + +static const struct fuse_opt fuse_mount_opts[] = { + FUSE_MOUNT_OPT("allow_other", allow_other), + FUSE_MOUNT_OPT("allow_root", allow_root), + FUSE_MOUNT_OPT("blkdev", blkdev), + FUSE_MOUNT_OPT("fsname=%s", fsname), + FUSE_OPT_KEY("allow_other", KEY_KERN_OPT), + FUSE_OPT_KEY("allow_root", KEY_ALLOW_ROOT), + FUSE_OPT_KEY("blkdev", KEY_FUSERMOUNT_OPT), + FUSE_OPT_KEY("fsname=", KEY_FUSERMOUNT_OPT), + FUSE_OPT_KEY("large_read", KEY_KERN_OPT), + FUSE_OPT_KEY("blksize=", KEY_KERN_OPT), + FUSE_OPT_KEY("default_permissions", KEY_KERN_OPT), + FUSE_OPT_KEY("max_read=", KEY_KERN_OPT), + FUSE_OPT_KEY("max_read=", FUSE_OPT_KEY_KEEP), + FUSE_OPT_KEY("user=", KEY_MTAB_OPT), + FUSE_OPT_KEY("-r", KEY_RO), + FUSE_OPT_KEY("ro", KEY_KERN_FLAG), + FUSE_OPT_KEY("rw", KEY_KERN_FLAG), + FUSE_OPT_KEY("suid", KEY_KERN_FLAG), + FUSE_OPT_KEY("nosuid", KEY_KERN_FLAG), + FUSE_OPT_KEY("dev", KEY_KERN_FLAG), + FUSE_OPT_KEY("nodev", KEY_KERN_FLAG), + FUSE_OPT_KEY("exec", KEY_KERN_FLAG), + FUSE_OPT_KEY("noexec", KEY_KERN_FLAG), + FUSE_OPT_KEY("async", KEY_KERN_FLAG), + FUSE_OPT_KEY("sync", KEY_KERN_FLAG), + FUSE_OPT_KEY("dirsync", KEY_KERN_FLAG), + FUSE_OPT_KEY("atime", KEY_KERN_FLAG), + FUSE_OPT_KEY("noatime", KEY_KERN_FLAG), + FUSE_OPT_KEY("-h", KEY_HELP), + FUSE_OPT_KEY("--help", KEY_HELP), + FUSE_OPT_KEY("-V", KEY_VERSION), + FUSE_OPT_KEY("--version", KEY_VERSION), + FUSE_OPT_END +}; + +struct mount_flags { + const char *opt; + unsigned long flag; + int on; +}; + +static struct mount_flags mount_flags[] = { + {"rw", MS_RDONLY, 0}, + {"ro", MS_RDONLY, 1}, + {"suid", MS_NOSUID, 0}, + {"nosuid", MS_NOSUID, 1}, + {"dev", MS_NODEV, 0}, + {"nodev", MS_NODEV, 1}, + {"exec", MS_NOEXEC, 0}, + {"noexec", MS_NOEXEC, 1}, + {"async", MS_SYNCHRONOUS, 0}, + {"sync", MS_SYNCHRONOUS, 1}, + {"atime", MS_NOATIME, 0}, + {"noatime", MS_NOATIME, 1}, + {"dirsync", MS_DIRSYNC, 1}, + {NULL, 0, 0} +}; + +static void set_mount_flag(const char *s, int *flags) +{ + int i; + + for (i = 0; mount_flags[i].opt != NULL; i++) { + const char *opt = mount_flags[i].opt; + if (strcmp(opt, s) == 0) { + if (mount_flags[i].on) + *flags |= mount_flags[i].flag; + else + *flags &= ~mount_flags[i].flag; + return; + } + } + fprintf(stderr, "fuse: internal error, can't find mount flag\n"); + abort(); +} + +static int fuse_mount_opt_proc(void *data, const char *arg, int key, + struct fuse_args *outargs) +{ + struct mount_opts *mo = data; + + switch (key) { + case KEY_ALLOW_ROOT: + if (fuse_opt_add_opt(&mo->kernel_opts, "allow_other") == -1 || + fuse_opt_add_arg(outargs, "-oallow_root") == -1) + return -1; + return 0; + + case KEY_RO: + arg = "ro"; + /* fall through */ + case KEY_KERN_FLAG: + set_mount_flag(arg, &mo->flags); + return 0; + + case KEY_KERN_OPT: + return fuse_opt_add_opt(&mo->kernel_opts, arg); + + case KEY_FUSERMOUNT_OPT: + return fuse_opt_add_opt(&mo->fusermount_opts, arg); + + case KEY_MTAB_OPT: + return fuse_opt_add_opt(&mo->mtab_opts, arg); + + case KEY_HELP: + mo->ishelp = 1; + break; + + case KEY_VERSION: + mo->ishelp = 1; + break; + } + return 1; +} + +void fuse_kern_unmount(const char *mountpoint, int fd) +{ + int res; + + if (!mountpoint) + return; + + if (fd != -1) { + struct pollfd pfd; + + pfd.fd = fd; + pfd.events = 0; + res = poll(&pfd, 1, 0); + /* If file poll returns POLLERR on the device file descriptor, + then the filesystem is already unmounted */ + if (res == 1 && (pfd.revents & POLLERR)) + return; + } + close(fd); + + fusermount(1, 0, 1, "", mountpoint); +} + +static int get_mnt_flag_opts(char **mnt_optsp, int flags) +{ + int i; + + if (!(flags & MS_RDONLY) && fuse_opt_add_opt(mnt_optsp, "rw") == -1) + return -1; + + for (i = 0; mount_flags[i].opt != NULL; i++) { + if (mount_flags[i].on && (flags & mount_flags[i].flag) && + fuse_opt_add_opt(mnt_optsp, mount_flags[i].opt) == -1) + return -1; + } + return 0; +} + +int fuse_kern_mount(const char *mountpoint, struct fuse_args *args) +{ + struct mount_opts mo; + int res = -1; + char *mnt_opts = NULL; + + memset(&mo, 0, sizeof(mo)); + if (getuid()) + mo.flags = MS_NOSUID | MS_NODEV; + + if (args && + fuse_opt_parse(args, &mo, fuse_mount_opts, fuse_mount_opt_proc) == -1) + return -1; + + if (mo.allow_other && mo.allow_root) { + fprintf(stderr, "fuse: 'allow_other' and 'allow_root' options are mutually exclusive\n"); + goto out; + } + res = 0; + if (mo.ishelp) + goto out; + + res = -1; + if (get_mnt_flag_opts(&mnt_opts, mo.flags) == -1) + goto out; + if (!(mo.flags & MS_NODEV) && fuse_opt_add_opt(&mnt_opts, "dev") == -1) + goto out; + if (!(mo.flags & MS_NOSUID) && fuse_opt_add_opt(&mnt_opts, "suid") == -1) + goto out; + if (mo.kernel_opts && fuse_opt_add_opt(&mnt_opts, mo.kernel_opts) == -1) + goto out; + if (mo.mtab_opts && fuse_opt_add_opt(&mnt_opts, mo.mtab_opts) == -1) + goto out; + if (mo.fusermount_opts && fuse_opt_add_opt(&mnt_opts, mo.fusermount_opts) < 0) + goto out; + + res = fusermount(0, 0, 0, mnt_opts ? mnt_opts : "", mountpoint); + +out: + free(mnt_opts); + free(mo.fsname); + free(mo.fusermount_opts); + free(mo.kernel_opts); + free(mo.mtab_opts); + return res; +} + diff --git a/libfuse-lite/mount_util.c b/libfuse-lite/mount_util.c new file mode 100755 index 0000000..75a7ee6 --- a/dev/null +++ b/libfuse-lite/mount_util.c @@ -0,0 +1,219 @@ +/* + FUSE: Filesystem in Userspace + Copyright (C) 2001-2007 Miklos Szeredi + + This program can be distributed under the terms of the GNU LGPLv2. + See the file COPYING.LIB. +*/ + +#include "config.h" +#include "mount_util.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int mtab_needs_update(const char *mnt) +{ + int res; + struct stat stbuf; + + /* If mtab is within new mount, don't touch it */ + if (strncmp(mnt, _PATH_MOUNTED, strlen(mnt)) == 0 && + _PATH_MOUNTED[strlen(mnt)] == '/') + return 0; + + /* + * Skip mtab update if /etc/mtab: + * + * - doesn't exist, + * - is a symlink, + * - is on a read-only filesystem. + */ + res = lstat(_PATH_MOUNTED, &stbuf); + if (res == -1) { + if (errno == ENOENT) + return 0; + } else { + if (S_ISLNK(stbuf.st_mode)) + return 0; + + res = access(_PATH_MOUNTED, W_OK); + if (res == -1 && errno == EROFS) + return 0; + } + + return 1; +} + +int fuse_mnt_add_mount(const char *progname, const char *fsname, + const char *mnt, const char *type, const char *opts) +{ + int res; + + if (!mtab_needs_update(mnt)) + return 0; + + res = fork(); + if (res == -1) { + fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno)); + return 0; + } + if (res == 0) { + char templ[] = "/tmp/fusermountXXXXXX"; + char *tmp; + + setuid(geteuid()); + + /* + * hide in a directory, where mount isn't able to resolve + * fsname as a valid path + */ + tmp = mkdtemp(templ); + if (!tmp) { + fprintf(stderr, "%s: failed to create temporary directory\n", + progname); + exit(1); + } + if (chdir(tmp)) { + fprintf(stderr, "%s: failed to chdir to %s: %s\n", + progname, tmp, strerror(errno)); + exit(1); + } + rmdir(tmp); + execl("/bin/mount", "/bin/mount", "-i", "-f", "-t", type, "-o", opts, + fsname, mnt, NULL); + fprintf(stderr, "%s: failed to execute /bin/mount: %s\n", progname, + strerror(errno)); + exit(1); + } + return 0; +} + +int fuse_mnt_umount(const char *progname, const char *mnt, int lazy) +{ + int res; + int status; + + if (!mtab_needs_update(mnt)) { + res = umount2(mnt, lazy ? 2 : 0); + if (res == -1) + fprintf(stderr, "%s: failed to unmount %s: %s\n", progname, + mnt, strerror(errno)); + return res; + } + + res = fork(); + if (res == -1) { + fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno)); + return -1; + } + if (res == 0) { + setuid(geteuid()); + execl("/bin/umount", "/bin/umount", "-i", mnt, lazy ? "-l" : NULL, + NULL); + fprintf(stderr, "%s: failed to execute /bin/umount: %s\n", progname, + strerror(errno)); + exit(1); + } + res = waitpid(res, &status, 0); + if (res == -1) { + fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno)); + return -1; + } + if (status != 0) + return -1; + + return 0; +} + +char *fuse_mnt_resolve_path(const char *progname, const char *orig) +{ + char buf[PATH_MAX]; + char *copy; + char *dst; + char *end; + char *lastcomp; + const char *toresolv; + + if (!orig[0]) { + fprintf(stderr, "%s: invalid mountpoint '%s'\n", progname, orig); + return NULL; + } + + copy = strdup(orig); + if (copy == NULL) { + fprintf(stderr, "%s: failed to allocate memory\n", progname); + return NULL; + } + + toresolv = copy; + lastcomp = NULL; + for (end = copy + strlen(copy) - 1; end > copy && *end == '/'; end --); + if (end[0] != '/') { + char *tmp; + end[1] = '\0'; + tmp = strrchr(copy, '/'); + if (tmp == NULL) { + lastcomp = copy; + toresolv = "."; + } else { + lastcomp = tmp + 1; + if (tmp == copy) + toresolv = "/"; + } + if (strcmp(lastcomp, ".") == 0 || strcmp(lastcomp, "..") == 0) { + lastcomp = NULL; + toresolv = copy; + } + else if (tmp) + tmp[0] = '\0'; + } + if (realpath(toresolv, buf) == NULL) { + fprintf(stderr, "%s: bad mount point %s: %s\n", progname, orig, + strerror(errno)); + free(copy); + return NULL; + } + if (lastcomp == NULL) + dst = strdup(buf); + else { + dst = (char *) malloc(strlen(buf) + 1 + strlen(lastcomp) + 1); + if (dst) { + unsigned buflen = strlen(buf); + if (buflen && buf[buflen-1] == '/') + sprintf(dst, "%s%s", buf, lastcomp); + else + sprintf(dst, "%s/%s", buf, lastcomp); + } + } + free(copy); + if (dst == NULL) + fprintf(stderr, "%s: failed to allocate memory\n", progname); + return dst; +} + +int fuse_mnt_check_fuseblk(void) +{ + char buf[256]; + FILE *f = fopen("/proc/filesystems", "r"); + if (!f) + return 1; + + while (fgets(buf, sizeof(buf), f)) + if (strstr(buf, "fuseblk\n")) { + fclose(f); + return 1; + } + + fclose(f); + return 0; +} diff --git a/libfuse-lite/mount_util.h b/libfuse-lite/mount_util.h new file mode 100755 index 0000000..d1b0899 --- a/dev/null +++ b/libfuse-lite/mount_util.h @@ -0,0 +1,22 @@ +/* + FUSE: Filesystem in Userspace + Copyright (C) 2001-2007 Miklos Szeredi + + This program can be distributed under the terms of the GNU LGPLv2. + See the file COPYING.LIB. +*/ + +#ifdef HAVE_SYS_TYPES_H +#include +#endif + + +int fuse_mnt_add_mount(const char *progname, const char *fsname, + const char *mnt, const char *type, const char *opts); +int fuse_mnt_umount(const char *progname, const char *mnt, int lazy); +char *fuse_mnt_resolve_path(const char *progname, const char *orig); +int fuse_mnt_check_fuseblk(void); + +int fusermount(int unmount, int quiet, int lazy, const char *opts, + const char *origmnt); + diff --git a/libntfs-3g/Makefile.am b/libntfs-3g/Makefile.am new file mode 100755 index 0000000..fe2fb9d --- a/dev/null +++ b/libntfs-3g/Makefile.am @@ -0,0 +1,79 @@ + +MAINTAINERCLEANFILES = $(srcdir)/Makefile.in + +if INSTALL_LIBRARY +rootlib_LTLIBRARIES=#Create directory +lib_LTLIBRARIES = libntfs-3g.la +pkgconfig_DATA = libntfs-3g.pc +else +noinst_LTLIBRARIES = libntfs-3g.la +endif + +libntfs_3g_la_CFLAGS = $(AM_CFLAGS) -I$(top_srcdir)/include/ntfs-3g + +libntfs_3g_la_LDFLAGS = -version-info $(LIBNTFS_3G_VERSION) -no-undefined + +if FUSE_INTERNAL +libntfs_3g_la_LIBADD = $(top_builddir)/libfuse-lite/libfuse-lite.la +endif + +libntfs_3g_la_SOURCES = \ + acls.c \ + attrib.c \ + attrlist.c \ + bitmap.c \ + bootsect.c \ + cache.c \ + collate.c \ + compat.c \ + compress.c \ + debug.c \ + device.c \ + dir.c \ + efs.c \ + index.c \ + inode.c \ + lcnalloc.c \ + logfile.c \ + logging.c \ + mft.c \ + misc.c \ + mst.c \ + object_id.c \ + reparse.c \ + runlist.c \ + security.c \ + unistr.c \ + volume.c + +if NTFS_DEVICE_DEFAULT_IO_OPS +if WINDOWS +libntfs_3g_la_SOURCES += win32_io.c +else +libntfs_3g_la_SOURCES += unix_io.c +endif +endif + +# We may need to move .so files to root +# And create ldscript or symbolic link from /usr +install-exec-hook: install-rootlibLTLIBRARIES +if INSTALL_LIBRARY + if [ ! "$(rootlibdir)" -ef "$(libdir)" ]; then \ + $(MV) -f "$(DESTDIR)/$(libdir)"/libntfs-3g.so* "$(DESTDIR)/$(rootlibdir)"; \ + fi +if GENERATE_LDSCRIPT + if [ ! "$(rootlibdir)" -ef "$(libdir)" ]; then \ + $(install_sh_PROGRAM) "libntfs-3g.script.so" "$(DESTDIR)/$(libdir)/libntfs-3g.so"; \ + fi +else + if [ ! "$(rootlibdir)" -ef "$(libdir)" ]; then \ + $(LN_S) "$(rootlibdir)/libntfs-3g.so" "$(DESTDIR)/$(libdir)/libntfs-3g.so"; \ + fi +endif +endif + +uninstall-local: +if INSTALL_LIBRARY + $(RM) -f "$(DESTDIR)/$(rootlibdir)"/libntfs-3g.so* +endif + diff --git a/libntfs-3g/Makefile.in b/libntfs-3g/Makefile.in new file mode 100755 index 0000000..6f50edd --- a/dev/null +++ b/libntfs-3g/Makefile.in @@ -0,0 +1,841 @@ +# Makefile.in generated by automake 1.10.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008 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@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@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 = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +@NTFS_DEVICE_DEFAULT_IO_OPS_TRUE@@WINDOWS_TRUE@am__append_1 = win32_io.c +@NTFS_DEVICE_DEFAULT_IO_OPS_TRUE@@WINDOWS_FALSE@am__append_2 = unix_io.c +subdir = libntfs-3g +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ + $(srcdir)/libntfs-3g.pc.in $(srcdir)/libntfs-3g.script.so.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = libntfs-3g.pc libntfs-3g.script.so +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 = `echo $$p | sed -e 's|^.*/||'`; +am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(rootlibdir)" \ + "$(DESTDIR)$(pkgconfigdir)" +libLTLIBRARIES_INSTALL = $(INSTALL) +rootlibLTLIBRARIES_INSTALL = $(INSTALL) +LTLIBRARIES = $(lib_LTLIBRARIES) $(noinst_LTLIBRARIES) \ + $(rootlib_LTLIBRARIES) +@FUSE_INTERNAL_TRUE@libntfs_3g_la_DEPENDENCIES = $(top_builddir)/libfuse-lite/libfuse-lite.la +am__libntfs_3g_la_SOURCES_DIST = acls.c attrib.c attrlist.c bitmap.c \ + bootsect.c cache.c collate.c compat.c compress.c debug.c \ + device.c dir.c efs.c index.c inode.c lcnalloc.c logfile.c \ + logging.c mft.c misc.c mst.c object_id.c reparse.c runlist.c \ + security.c unistr.c volume.c win32_io.c unix_io.c +@NTFS_DEVICE_DEFAULT_IO_OPS_TRUE@@WINDOWS_TRUE@am__objects_1 = libntfs_3g_la-win32_io.lo +@NTFS_DEVICE_DEFAULT_IO_OPS_TRUE@@WINDOWS_FALSE@am__objects_2 = libntfs_3g_la-unix_io.lo +am_libntfs_3g_la_OBJECTS = libntfs_3g_la-acls.lo \ + libntfs_3g_la-attrib.lo libntfs_3g_la-attrlist.lo \ + libntfs_3g_la-bitmap.lo libntfs_3g_la-bootsect.lo \ + libntfs_3g_la-cache.lo libntfs_3g_la-collate.lo \ + libntfs_3g_la-compat.lo libntfs_3g_la-compress.lo \ + libntfs_3g_la-debug.lo libntfs_3g_la-device.lo \ + libntfs_3g_la-dir.lo libntfs_3g_la-efs.lo \ + libntfs_3g_la-index.lo libntfs_3g_la-inode.lo \ + libntfs_3g_la-lcnalloc.lo libntfs_3g_la-logfile.lo \ + libntfs_3g_la-logging.lo libntfs_3g_la-mft.lo \ + libntfs_3g_la-misc.lo libntfs_3g_la-mst.lo \ + libntfs_3g_la-object_id.lo libntfs_3g_la-reparse.lo \ + libntfs_3g_la-runlist.lo libntfs_3g_la-security.lo \ + libntfs_3g_la-unistr.lo libntfs_3g_la-volume.lo \ + $(am__objects_1) $(am__objects_2) +libntfs_3g_la_OBJECTS = $(am_libntfs_3g_la_OBJECTS) +libntfs_3g_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(libntfs_3g_la_CFLAGS) \ + $(CFLAGS) $(libntfs_3g_la_LDFLAGS) $(LDFLAGS) -o $@ +@INSTALL_LIBRARY_FALSE@am_libntfs_3g_la_rpath = +@INSTALL_LIBRARY_TRUE@am_libntfs_3g_la_rpath = -rpath $(libdir) +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(libntfs_3g_la_SOURCES) +DIST_SOURCES = $(am__libntfs_3g_la_SOURCES_DIST) +pkgconfigDATA_INSTALL = $(INSTALL_DATA) +DATA = $(pkgconfig_DATA) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DSYMUTIL = @DSYMUTIL@ +ECHO = @ECHO@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +F77 = @F77@ +FFLAGS = @FFLAGS@ +FUSE_MODULE_CFLAGS = @FUSE_MODULE_CFLAGS@ +FUSE_MODULE_LIBS = @FUSE_MODULE_LIBS@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDCONFIG = @LDCONFIG@ +LDFLAGS = @LDFLAGS@ +LIBFUSE_LITE_LIBS = @LIBFUSE_LITE_LIBS@ +LIBNTFS_3G_VERSION = @LIBNTFS_3G_VERSION@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MV = @MV@ +NMEDIT = @NMEDIT@ +OBJEXT = @OBJEXT@ +OUTPUT_FORMAT = @OUTPUT_FORMAT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PKG_CONFIG = @PKG_CONFIG@ +RANLIB = @RANLIB@ +RM = @RM@ +SED = @SED@ +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_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_F77 = @ac_ct_F77@ +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 = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +ntfs3gincludedir = @ntfs3gincludedir@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgconfigdir = @pkgconfigdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +rootbindir = @rootbindir@ +rootlibdir = @rootlibdir@ +rootsbindir = @rootsbindir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +MAINTAINERCLEANFILES = $(srcdir)/Makefile.in +@INSTALL_LIBRARY_TRUE@rootlib_LTLIBRARIES = #Create directory +@INSTALL_LIBRARY_TRUE@lib_LTLIBRARIES = libntfs-3g.la +@INSTALL_LIBRARY_TRUE@pkgconfig_DATA = libntfs-3g.pc +@INSTALL_LIBRARY_FALSE@noinst_LTLIBRARIES = libntfs-3g.la +libntfs_3g_la_CFLAGS = $(AM_CFLAGS) -I$(top_srcdir)/include/ntfs-3g +libntfs_3g_la_LDFLAGS = -version-info $(LIBNTFS_3G_VERSION) -no-undefined +@FUSE_INTERNAL_TRUE@libntfs_3g_la_LIBADD = $(top_builddir)/libfuse-lite/libfuse-lite.la +libntfs_3g_la_SOURCES = acls.c attrib.c attrlist.c bitmap.c bootsect.c \ + cache.c collate.c compat.c compress.c debug.c device.c dir.c \ + efs.c index.c inode.c lcnalloc.c logfile.c logging.c mft.c \ + misc.c mst.c object_id.c reparse.c runlist.c security.c \ + unistr.c volume.c $(am__append_1) $(am__append_2) +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu libntfs-3g/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu libntfs-3g/Makefile +.PRECIOUS: 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__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +libntfs-3g.pc: $(top_builddir)/config.status $(srcdir)/libntfs-3g.pc.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +libntfs-3g.script.so: $(top_builddir)/config.status $(srcdir)/libntfs-3g.script.so.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + if test -f $$p; then \ + f=$(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(libdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(libdir)/$$f"; \ + else :; fi; \ + done + +uninstall-libLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + p=$(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$p'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$p"; \ + done + +clean-libLTLIBRARIES: + -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +install-rootlibLTLIBRARIES: $(rootlib_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(rootlibdir)" || $(MKDIR_P) "$(DESTDIR)$(rootlibdir)" + @list='$(rootlib_LTLIBRARIES)'; for p in $$list; do \ + if test -f $$p; then \ + f=$(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(rootlibLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(rootlibdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(rootlibLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(rootlibdir)/$$f"; \ + else :; fi; \ + done + +uninstall-rootlibLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(rootlib_LTLIBRARIES)'; for p in $$list; do \ + p=$(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(rootlibdir)/$$p'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(rootlibdir)/$$p"; \ + done + +clean-rootlibLTLIBRARIES: + -test -z "$(rootlib_LTLIBRARIES)" || rm -f $(rootlib_LTLIBRARIES) + @list='$(rootlib_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libntfs-3g.la: $(libntfs_3g_la_OBJECTS) $(libntfs_3g_la_DEPENDENCIES) + $(libntfs_3g_la_LINK) $(am_libntfs_3g_la_rpath) $(libntfs_3g_la_OBJECTS) $(libntfs_3g_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libntfs_3g_la-acls.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libntfs_3g_la-attrib.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libntfs_3g_la-attrlist.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libntfs_3g_la-bitmap.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libntfs_3g_la-bootsect.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libntfs_3g_la-cache.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libntfs_3g_la-collate.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libntfs_3g_la-compat.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libntfs_3g_la-compress.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libntfs_3g_la-debug.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libntfs_3g_la-device.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libntfs_3g_la-dir.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libntfs_3g_la-efs.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libntfs_3g_la-index.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libntfs_3g_la-inode.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libntfs_3g_la-lcnalloc.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libntfs_3g_la-logfile.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libntfs_3g_la-logging.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libntfs_3g_la-mft.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libntfs_3g_la-misc.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libntfs_3g_la-mst.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libntfs_3g_la-object_id.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libntfs_3g_la-reparse.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libntfs_3g_la-runlist.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libntfs_3g_la-security.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libntfs_3g_la-unistr.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libntfs_3g_la-unix_io.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libntfs_3g_la-volume.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libntfs_3g_la-win32_io.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +libntfs_3g_la-acls.lo: acls.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libntfs_3g_la_CFLAGS) $(CFLAGS) -MT libntfs_3g_la-acls.lo -MD -MP -MF $(DEPDIR)/libntfs_3g_la-acls.Tpo -c -o libntfs_3g_la-acls.lo `test -f 'acls.c' || echo '$(srcdir)/'`acls.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libntfs_3g_la-acls.Tpo $(DEPDIR)/libntfs_3g_la-acls.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='acls.c' object='libntfs_3g_la-acls.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libntfs_3g_la_CFLAGS) $(CFLAGS) -c -o libntfs_3g_la-acls.lo `test -f 'acls.c' || echo '$(srcdir)/'`acls.c + +libntfs_3g_la-attrib.lo: attrib.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libntfs_3g_la_CFLAGS) $(CFLAGS) -MT libntfs_3g_la-attrib.lo -MD -MP -MF $(DEPDIR)/libntfs_3g_la-attrib.Tpo -c -o libntfs_3g_la-attrib.lo `test -f 'attrib.c' || echo '$(srcdir)/'`attrib.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libntfs_3g_la-attrib.Tpo $(DEPDIR)/libntfs_3g_la-attrib.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='attrib.c' object='libntfs_3g_la-attrib.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libntfs_3g_la_CFLAGS) $(CFLAGS) -c -o libntfs_3g_la-attrib.lo `test -f 'attrib.c' || echo '$(srcdir)/'`attrib.c + +libntfs_3g_la-attrlist.lo: attrlist.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libntfs_3g_la_CFLAGS) $(CFLAGS) -MT libntfs_3g_la-attrlist.lo -MD -MP -MF $(DEPDIR)/libntfs_3g_la-attrlist.Tpo -c -o libntfs_3g_la-attrlist.lo `test -f 'attrlist.c' || echo '$(srcdir)/'`attrlist.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libntfs_3g_la-attrlist.Tpo $(DEPDIR)/libntfs_3g_la-attrlist.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='attrlist.c' object='libntfs_3g_la-attrlist.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libntfs_3g_la_CFLAGS) $(CFLAGS) -c -o libntfs_3g_la-attrlist.lo `test -f 'attrlist.c' || echo '$(srcdir)/'`attrlist.c + +libntfs_3g_la-bitmap.lo: bitmap.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libntfs_3g_la_CFLAGS) $(CFLAGS) -MT libntfs_3g_la-bitmap.lo -MD -MP -MF $(DEPDIR)/libntfs_3g_la-bitmap.Tpo -c -o libntfs_3g_la-bitmap.lo `test -f 'bitmap.c' || echo '$(srcdir)/'`bitmap.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libntfs_3g_la-bitmap.Tpo $(DEPDIR)/libntfs_3g_la-bitmap.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='bitmap.c' object='libntfs_3g_la-bitmap.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libntfs_3g_la_CFLAGS) $(CFLAGS) -c -o libntfs_3g_la-bitmap.lo `test -f 'bitmap.c' || echo '$(srcdir)/'`bitmap.c + +libntfs_3g_la-bootsect.lo: bootsect.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libntfs_3g_la_CFLAGS) $(CFLAGS) -MT libntfs_3g_la-bootsect.lo -MD -MP -MF $(DEPDIR)/libntfs_3g_la-bootsect.Tpo -c -o libntfs_3g_la-bootsect.lo `test -f 'bootsect.c' || echo '$(srcdir)/'`bootsect.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libntfs_3g_la-bootsect.Tpo $(DEPDIR)/libntfs_3g_la-bootsect.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='bootsect.c' object='libntfs_3g_la-bootsect.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libntfs_3g_la_CFLAGS) $(CFLAGS) -c -o libntfs_3g_la-bootsect.lo `test -f 'bootsect.c' || echo '$(srcdir)/'`bootsect.c + +libntfs_3g_la-cache.lo: cache.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libntfs_3g_la_CFLAGS) $(CFLAGS) -MT libntfs_3g_la-cache.lo -MD -MP -MF $(DEPDIR)/libntfs_3g_la-cache.Tpo -c -o libntfs_3g_la-cache.lo `test -f 'cache.c' || echo '$(srcdir)/'`cache.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libntfs_3g_la-cache.Tpo $(DEPDIR)/libntfs_3g_la-cache.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='cache.c' object='libntfs_3g_la-cache.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libntfs_3g_la_CFLAGS) $(CFLAGS) -c -o libntfs_3g_la-cache.lo `test -f 'cache.c' || echo '$(srcdir)/'`cache.c + +libntfs_3g_la-collate.lo: collate.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libntfs_3g_la_CFLAGS) $(CFLAGS) -MT libntfs_3g_la-collate.lo -MD -MP -MF $(DEPDIR)/libntfs_3g_la-collate.Tpo -c -o libntfs_3g_la-collate.lo `test -f 'collate.c' || echo '$(srcdir)/'`collate.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libntfs_3g_la-collate.Tpo $(DEPDIR)/libntfs_3g_la-collate.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='collate.c' object='libntfs_3g_la-collate.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libntfs_3g_la_CFLAGS) $(CFLAGS) -c -o libntfs_3g_la-collate.lo `test -f 'collate.c' || echo '$(srcdir)/'`collate.c + +libntfs_3g_la-compat.lo: compat.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libntfs_3g_la_CFLAGS) $(CFLAGS) -MT libntfs_3g_la-compat.lo -MD -MP -MF $(DEPDIR)/libntfs_3g_la-compat.Tpo -c -o libntfs_3g_la-compat.lo `test -f 'compat.c' || echo '$(srcdir)/'`compat.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libntfs_3g_la-compat.Tpo $(DEPDIR)/libntfs_3g_la-compat.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='compat.c' object='libntfs_3g_la-compat.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libntfs_3g_la_CFLAGS) $(CFLAGS) -c -o libntfs_3g_la-compat.lo `test -f 'compat.c' || echo '$(srcdir)/'`compat.c + +libntfs_3g_la-compress.lo: compress.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libntfs_3g_la_CFLAGS) $(CFLAGS) -MT libntfs_3g_la-compress.lo -MD -MP -MF $(DEPDIR)/libntfs_3g_la-compress.Tpo -c -o libntfs_3g_la-compress.lo `test -f 'compress.c' || echo '$(srcdir)/'`compress.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libntfs_3g_la-compress.Tpo $(DEPDIR)/libntfs_3g_la-compress.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='compress.c' object='libntfs_3g_la-compress.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libntfs_3g_la_CFLAGS) $(CFLAGS) -c -o libntfs_3g_la-compress.lo `test -f 'compress.c' || echo '$(srcdir)/'`compress.c + +libntfs_3g_la-debug.lo: debug.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libntfs_3g_la_CFLAGS) $(CFLAGS) -MT libntfs_3g_la-debug.lo -MD -MP -MF $(DEPDIR)/libntfs_3g_la-debug.Tpo -c -o libntfs_3g_la-debug.lo `test -f 'debug.c' || echo '$(srcdir)/'`debug.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libntfs_3g_la-debug.Tpo $(DEPDIR)/libntfs_3g_la-debug.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='debug.c' object='libntfs_3g_la-debug.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libntfs_3g_la_CFLAGS) $(CFLAGS) -c -o libntfs_3g_la-debug.lo `test -f 'debug.c' || echo '$(srcdir)/'`debug.c + +libntfs_3g_la-device.lo: device.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libntfs_3g_la_CFLAGS) $(CFLAGS) -MT libntfs_3g_la-device.lo -MD -MP -MF $(DEPDIR)/libntfs_3g_la-device.Tpo -c -o libntfs_3g_la-device.lo `test -f 'device.c' || echo '$(srcdir)/'`device.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libntfs_3g_la-device.Tpo $(DEPDIR)/libntfs_3g_la-device.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='device.c' object='libntfs_3g_la-device.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libntfs_3g_la_CFLAGS) $(CFLAGS) -c -o libntfs_3g_la-device.lo `test -f 'device.c' || echo '$(srcdir)/'`device.c + +libntfs_3g_la-dir.lo: dir.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libntfs_3g_la_CFLAGS) $(CFLAGS) -MT libntfs_3g_la-dir.lo -MD -MP -MF $(DEPDIR)/libntfs_3g_la-dir.Tpo -c -o libntfs_3g_la-dir.lo `test -f 'dir.c' || echo '$(srcdir)/'`dir.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libntfs_3g_la-dir.Tpo $(DEPDIR)/libntfs_3g_la-dir.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='dir.c' object='libntfs_3g_la-dir.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libntfs_3g_la_CFLAGS) $(CFLAGS) -c -o libntfs_3g_la-dir.lo `test -f 'dir.c' || echo '$(srcdir)/'`dir.c + +libntfs_3g_la-efs.lo: efs.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libntfs_3g_la_CFLAGS) $(CFLAGS) -MT libntfs_3g_la-efs.lo -MD -MP -MF $(DEPDIR)/libntfs_3g_la-efs.Tpo -c -o libntfs_3g_la-efs.lo `test -f 'efs.c' || echo '$(srcdir)/'`efs.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libntfs_3g_la-efs.Tpo $(DEPDIR)/libntfs_3g_la-efs.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='efs.c' object='libntfs_3g_la-efs.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libntfs_3g_la_CFLAGS) $(CFLAGS) -c -o libntfs_3g_la-efs.lo `test -f 'efs.c' || echo '$(srcdir)/'`efs.c + +libntfs_3g_la-index.lo: index.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libntfs_3g_la_CFLAGS) $(CFLAGS) -MT libntfs_3g_la-index.lo -MD -MP -MF $(DEPDIR)/libntfs_3g_la-index.Tpo -c -o libntfs_3g_la-index.lo `test -f 'index.c' || echo '$(srcdir)/'`index.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libntfs_3g_la-index.Tpo $(DEPDIR)/libntfs_3g_la-index.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='index.c' object='libntfs_3g_la-index.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libntfs_3g_la_CFLAGS) $(CFLAGS) -c -o libntfs_3g_la-index.lo `test -f 'index.c' || echo '$(srcdir)/'`index.c + +libntfs_3g_la-inode.lo: inode.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libntfs_3g_la_CFLAGS) $(CFLAGS) -MT libntfs_3g_la-inode.lo -MD -MP -MF $(DEPDIR)/libntfs_3g_la-inode.Tpo -c -o libntfs_3g_la-inode.lo `test -f 'inode.c' || echo '$(srcdir)/'`inode.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libntfs_3g_la-inode.Tpo $(DEPDIR)/libntfs_3g_la-inode.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='inode.c' object='libntfs_3g_la-inode.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libntfs_3g_la_CFLAGS) $(CFLAGS) -c -o libntfs_3g_la-inode.lo `test -f 'inode.c' || echo '$(srcdir)/'`inode.c + +libntfs_3g_la-lcnalloc.lo: lcnalloc.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libntfs_3g_la_CFLAGS) $(CFLAGS) -MT libntfs_3g_la-lcnalloc.lo -MD -MP -MF $(DEPDIR)/libntfs_3g_la-lcnalloc.Tpo -c -o libntfs_3g_la-lcnalloc.lo `test -f 'lcnalloc.c' || echo '$(srcdir)/'`lcnalloc.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libntfs_3g_la-lcnalloc.Tpo $(DEPDIR)/libntfs_3g_la-lcnalloc.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='lcnalloc.c' object='libntfs_3g_la-lcnalloc.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libntfs_3g_la_CFLAGS) $(CFLAGS) -c -o libntfs_3g_la-lcnalloc.lo `test -f 'lcnalloc.c' || echo '$(srcdir)/'`lcnalloc.c + +libntfs_3g_la-logfile.lo: logfile.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libntfs_3g_la_CFLAGS) $(CFLAGS) -MT libntfs_3g_la-logfile.lo -MD -MP -MF $(DEPDIR)/libntfs_3g_la-logfile.Tpo -c -o libntfs_3g_la-logfile.lo `test -f 'logfile.c' || echo '$(srcdir)/'`logfile.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libntfs_3g_la-logfile.Tpo $(DEPDIR)/libntfs_3g_la-logfile.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='logfile.c' object='libntfs_3g_la-logfile.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libntfs_3g_la_CFLAGS) $(CFLAGS) -c -o libntfs_3g_la-logfile.lo `test -f 'logfile.c' || echo '$(srcdir)/'`logfile.c + +libntfs_3g_la-logging.lo: logging.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libntfs_3g_la_CFLAGS) $(CFLAGS) -MT libntfs_3g_la-logging.lo -MD -MP -MF $(DEPDIR)/libntfs_3g_la-logging.Tpo -c -o libntfs_3g_la-logging.lo `test -f 'logging.c' || echo '$(srcdir)/'`logging.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libntfs_3g_la-logging.Tpo $(DEPDIR)/libntfs_3g_la-logging.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='logging.c' object='libntfs_3g_la-logging.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libntfs_3g_la_CFLAGS) $(CFLAGS) -c -o libntfs_3g_la-logging.lo `test -f 'logging.c' || echo '$(srcdir)/'`logging.c + +libntfs_3g_la-mft.lo: mft.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libntfs_3g_la_CFLAGS) $(CFLAGS) -MT libntfs_3g_la-mft.lo -MD -MP -MF $(DEPDIR)/libntfs_3g_la-mft.Tpo -c -o libntfs_3g_la-mft.lo `test -f 'mft.c' || echo '$(srcdir)/'`mft.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libntfs_3g_la-mft.Tpo $(DEPDIR)/libntfs_3g_la-mft.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='mft.c' object='libntfs_3g_la-mft.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libntfs_3g_la_CFLAGS) $(CFLAGS) -c -o libntfs_3g_la-mft.lo `test -f 'mft.c' || echo '$(srcdir)/'`mft.c + +libntfs_3g_la-misc.lo: misc.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libntfs_3g_la_CFLAGS) $(CFLAGS) -MT libntfs_3g_la-misc.lo -MD -MP -MF $(DEPDIR)/libntfs_3g_la-misc.Tpo -c -o libntfs_3g_la-misc.lo `test -f 'misc.c' || echo '$(srcdir)/'`misc.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libntfs_3g_la-misc.Tpo $(DEPDIR)/libntfs_3g_la-misc.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='misc.c' object='libntfs_3g_la-misc.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libntfs_3g_la_CFLAGS) $(CFLAGS) -c -o libntfs_3g_la-misc.lo `test -f 'misc.c' || echo '$(srcdir)/'`misc.c + +libntfs_3g_la-mst.lo: mst.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libntfs_3g_la_CFLAGS) $(CFLAGS) -MT libntfs_3g_la-mst.lo -MD -MP -MF $(DEPDIR)/libntfs_3g_la-mst.Tpo -c -o libntfs_3g_la-mst.lo `test -f 'mst.c' || echo '$(srcdir)/'`mst.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libntfs_3g_la-mst.Tpo $(DEPDIR)/libntfs_3g_la-mst.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='mst.c' object='libntfs_3g_la-mst.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libntfs_3g_la_CFLAGS) $(CFLAGS) -c -o libntfs_3g_la-mst.lo `test -f 'mst.c' || echo '$(srcdir)/'`mst.c + +libntfs_3g_la-object_id.lo: object_id.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libntfs_3g_la_CFLAGS) $(CFLAGS) -MT libntfs_3g_la-object_id.lo -MD -MP -MF $(DEPDIR)/libntfs_3g_la-object_id.Tpo -c -o libntfs_3g_la-object_id.lo `test -f 'object_id.c' || echo '$(srcdir)/'`object_id.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libntfs_3g_la-object_id.Tpo $(DEPDIR)/libntfs_3g_la-object_id.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='object_id.c' object='libntfs_3g_la-object_id.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libntfs_3g_la_CFLAGS) $(CFLAGS) -c -o libntfs_3g_la-object_id.lo `test -f 'object_id.c' || echo '$(srcdir)/'`object_id.c + +libntfs_3g_la-reparse.lo: reparse.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libntfs_3g_la_CFLAGS) $(CFLAGS) -MT libntfs_3g_la-reparse.lo -MD -MP -MF $(DEPDIR)/libntfs_3g_la-reparse.Tpo -c -o libntfs_3g_la-reparse.lo `test -f 'reparse.c' || echo '$(srcdir)/'`reparse.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libntfs_3g_la-reparse.Tpo $(DEPDIR)/libntfs_3g_la-reparse.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='reparse.c' object='libntfs_3g_la-reparse.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libntfs_3g_la_CFLAGS) $(CFLAGS) -c -o libntfs_3g_la-reparse.lo `test -f 'reparse.c' || echo '$(srcdir)/'`reparse.c + +libntfs_3g_la-runlist.lo: runlist.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libntfs_3g_la_CFLAGS) $(CFLAGS) -MT libntfs_3g_la-runlist.lo -MD -MP -MF $(DEPDIR)/libntfs_3g_la-runlist.Tpo -c -o libntfs_3g_la-runlist.lo `test -f 'runlist.c' || echo '$(srcdir)/'`runlist.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libntfs_3g_la-runlist.Tpo $(DEPDIR)/libntfs_3g_la-runlist.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runlist.c' object='libntfs_3g_la-runlist.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libntfs_3g_la_CFLAGS) $(CFLAGS) -c -o libntfs_3g_la-runlist.lo `test -f 'runlist.c' || echo '$(srcdir)/'`runlist.c + +libntfs_3g_la-security.lo: security.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libntfs_3g_la_CFLAGS) $(CFLAGS) -MT libntfs_3g_la-security.lo -MD -MP -MF $(DEPDIR)/libntfs_3g_la-security.Tpo -c -o libntfs_3g_la-security.lo `test -f 'security.c' || echo '$(srcdir)/'`security.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libntfs_3g_la-security.Tpo $(DEPDIR)/libntfs_3g_la-security.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='security.c' object='libntfs_3g_la-security.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libntfs_3g_la_CFLAGS) $(CFLAGS) -c -o libntfs_3g_la-security.lo `test -f 'security.c' || echo '$(srcdir)/'`security.c + +libntfs_3g_la-unistr.lo: unistr.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libntfs_3g_la_CFLAGS) $(CFLAGS) -MT libntfs_3g_la-unistr.lo -MD -MP -MF $(DEPDIR)/libntfs_3g_la-unistr.Tpo -c -o libntfs_3g_la-unistr.lo `test -f 'unistr.c' || echo '$(srcdir)/'`unistr.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libntfs_3g_la-unistr.Tpo $(DEPDIR)/libntfs_3g_la-unistr.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='unistr.c' object='libntfs_3g_la-unistr.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libntfs_3g_la_CFLAGS) $(CFLAGS) -c -o libntfs_3g_la-unistr.lo `test -f 'unistr.c' || echo '$(srcdir)/'`unistr.c + +libntfs_3g_la-volume.lo: volume.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libntfs_3g_la_CFLAGS) $(CFLAGS) -MT libntfs_3g_la-volume.lo -MD -MP -MF $(DEPDIR)/libntfs_3g_la-volume.Tpo -c -o libntfs_3g_la-volume.lo `test -f 'volume.c' || echo '$(srcdir)/'`volume.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libntfs_3g_la-volume.Tpo $(DEPDIR)/libntfs_3g_la-volume.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='volume.c' object='libntfs_3g_la-volume.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libntfs_3g_la_CFLAGS) $(CFLAGS) -c -o libntfs_3g_la-volume.lo `test -f 'volume.c' || echo '$(srcdir)/'`volume.c + +libntfs_3g_la-win32_io.lo: win32_io.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libntfs_3g_la_CFLAGS) $(CFLAGS) -MT libntfs_3g_la-win32_io.lo -MD -MP -MF $(DEPDIR)/libntfs_3g_la-win32_io.Tpo -c -o libntfs_3g_la-win32_io.lo `test -f 'win32_io.c' || echo '$(srcdir)/'`win32_io.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libntfs_3g_la-win32_io.Tpo $(DEPDIR)/libntfs_3g_la-win32_io.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='win32_io.c' object='libntfs_3g_la-win32_io.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libntfs_3g_la_CFLAGS) $(CFLAGS) -c -o libntfs_3g_la-win32_io.lo `test -f 'win32_io.c' || echo '$(srcdir)/'`win32_io.c + +libntfs_3g_la-unix_io.lo: unix_io.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libntfs_3g_la_CFLAGS) $(CFLAGS) -MT libntfs_3g_la-unix_io.lo -MD -MP -MF $(DEPDIR)/libntfs_3g_la-unix_io.Tpo -c -o libntfs_3g_la-unix_io.lo `test -f 'unix_io.c' || echo '$(srcdir)/'`unix_io.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libntfs_3g_la-unix_io.Tpo $(DEPDIR)/libntfs_3g_la-unix_io.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='unix_io.c' object='libntfs_3g_la-unix_io.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libntfs_3g_la_CFLAGS) $(CFLAGS) -c -o libntfs_3g_la-unix_io.lo `test -f 'unix_io.c' || echo '$(srcdir)/'`unix_io.c + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-pkgconfigDATA: $(pkgconfig_DATA) + @$(NORMAL_INSTALL) + test -z "$(pkgconfigdir)" || $(MKDIR_P) "$(DESTDIR)$(pkgconfigdir)" + @list='$(pkgconfig_DATA)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f=$(am__strip_dir) \ + echo " $(pkgconfigDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(pkgconfigdir)/$$f'"; \ + $(pkgconfigDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(pkgconfigdir)/$$f"; \ + done + +uninstall-pkgconfigDATA: + @$(NORMAL_UNINSTALL) + @list='$(pkgconfig_DATA)'; for p in $$list; do \ + f=$(am__strip_dir) \ + echo " rm -f '$(DESTDIR)$(pkgconfigdir)/$$f'"; \ + rm -f "$(DESTDIR)$(pkgconfigdir)/$$f"; \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(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 $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$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 $(LTLIBRARIES) $(DATA) +installdirs: + for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(rootlibdir)" "$(DESTDIR)$(pkgconfigdir)"; 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: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) +clean: clean-am + +clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ + clean-noinstLTLIBRARIES clean-rootlibLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-pkgconfigDATA install-rootlibLTLIBRARIES + +install-dvi: install-dvi-am + +install-exec-am: install-libLTLIBRARIES + @$(NORMAL_INSTALL) + $(MAKE) $(AM_MAKEFLAGS) install-exec-hook + +install-html: install-html-am + +install-info: install-info-am + +install-man: + +install-pdf: install-pdf-am + +install-ps: install-ps-am + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-libLTLIBRARIES uninstall-local \ + uninstall-pkgconfigDATA uninstall-rootlibLTLIBRARIES + +.MAKE: install-am install-exec-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libLTLIBRARIES clean-libtool clean-noinstLTLIBRARIES \ + clean-rootlibLTLIBRARIES ctags distclean distclean-compile \ + distclean-generic distclean-libtool 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-exec-hook install-html \ + install-html-am install-info install-info-am \ + install-libLTLIBRARIES install-man install-pdf install-pdf-am \ + install-pkgconfigDATA install-ps install-ps-am \ + install-rootlibLTLIBRARIES install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-libLTLIBRARIES \ + uninstall-local uninstall-pkgconfigDATA \ + uninstall-rootlibLTLIBRARIES + + +# We may need to move .so files to root +# And create ldscript or symbolic link from /usr +install-exec-hook: install-rootlibLTLIBRARIES +@INSTALL_LIBRARY_TRUE@ if [ ! "$(rootlibdir)" -ef "$(libdir)" ]; then \ +@INSTALL_LIBRARY_TRUE@ $(MV) -f "$(DESTDIR)/$(libdir)"/libntfs-3g.so* "$(DESTDIR)/$(rootlibdir)"; \ +@INSTALL_LIBRARY_TRUE@ fi +@GENERATE_LDSCRIPT_TRUE@@INSTALL_LIBRARY_TRUE@ if [ ! "$(rootlibdir)" -ef "$(libdir)" ]; then \ +@GENERATE_LDSCRIPT_TRUE@@INSTALL_LIBRARY_TRUE@ $(install_sh_PROGRAM) "libntfs-3g.script.so" "$(DESTDIR)/$(libdir)/libntfs-3g.so"; \ +@GENERATE_LDSCRIPT_TRUE@@INSTALL_LIBRARY_TRUE@ fi +@GENERATE_LDSCRIPT_FALSE@@INSTALL_LIBRARY_TRUE@ if [ ! "$(rootlibdir)" -ef "$(libdir)" ]; then \ +@GENERATE_LDSCRIPT_FALSE@@INSTALL_LIBRARY_TRUE@ $(LN_S) "$(rootlibdir)/libntfs-3g.so" "$(DESTDIR)/$(libdir)/libntfs-3g.so"; \ +@GENERATE_LDSCRIPT_FALSE@@INSTALL_LIBRARY_TRUE@ fi + +uninstall-local: +@INSTALL_LIBRARY_TRUE@ $(RM) -f "$(DESTDIR)/$(rootlibdir)"/libntfs-3g.so* +# 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: diff --git a/libntfs-3g/acls.c b/libntfs-3g/acls.c new file mode 100755 index 0000000..11054ba --- a/dev/null +++ b/libntfs-3g/acls.c @@ -0,0 +1,4296 @@ +/** + * acls.c - General function to process NTFS ACLs + * + * This module is part of ntfs-3g library, but may also be + * integrated in tools running over Linux or Windows + * + * Copyright (c) 2007-2009 Jean-Pierre Andre + * + * This program/include file 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/include file 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 (in the main directory of the NTFS-3G + * distribution in the file COPYING); if not, write to the Free Software + * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifdef HAVE_CONFIG_H + /* + * integration into ntfs-3g + */ +#include "config.h" + +#ifdef HAVE_STDIO_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_ERRNO_H +#include +#endif +#ifdef HAVE_SYS_STAT_H +#include +#endif +#ifdef HAVE_FCNTL_H +#include +#endif +#ifdef HAVE_SYSLOG_H +#include +#endif +#include +#include +#include + +#include "types.h" +#include "layout.h" +#include "security.h" +#include "acls.h" +#include "misc.h" +#else + + /* + * integration into secaudit, check whether Win32, + * may have to be adapted to compiler or something else + */ + +#ifndef WIN32 +#if defined(__WIN32) | defined(__WIN32__) | defined(WNSC) +#define WIN32 1 +#endif +#endif + +#include +#include +#include +#include +#include +#ifdef HAVE_SYS_TYPES_H +#include +#endif + +#include + + /* + * integration into secaudit/Win32 + */ +#ifdef WIN32 +#include +#include +#define __LITTLE_ENDIAN 1234 +#define __BYTE_ORDER __LITTLE_ENDIAN +#else + /* + * integration into secaudit/STSC + */ +#ifdef STSC +#include +#undef __BYTE_ORDER +#define __BYTE_ORDER __BIG_ENDIAN +#else + /* + * integration into secaudit/Linux + */ +#include +#include +#include +#include +#endif /* STSC */ +#endif /* WIN32 */ +//#include "secaudit.h" +#endif /* HAVE_CONFIG_H */ + +/* + * A few useful constants + */ + +/* + * null SID (S-1-0-0) + */ + +static const char nullsidbytes[] = { + 1, /* revision */ + 1, /* auth count */ + 0, 0, 0, 0, 0, 0, /* base */ + 0, 0, 0, 0 /* 1st level */ + }; + +static const SID *nullsid = (const SID*)nullsidbytes; + +/* + * SID for world (S-1-1-0) + */ + +static const char worldsidbytes[] = { + 1, /* revision */ + 1, /* auth count */ + 0, 0, 0, 0, 0, 1, /* base */ + 0, 0, 0, 0 /* 1st level */ +} ; + +const SID *worldsid = (const SID*)worldsidbytes; + +/* + * SID for administrator + */ + +static const char adminsidbytes[] = { + 1, /* revision */ + 2, /* auth count */ + 0, 0, 0, 0, 0, 5, /* base */ + 32, 0, 0, 0, /* 1st level */ + 32, 2, 0, 0 /* 2nd level */ +}; + +const SID *adminsid = (const SID*)adminsidbytes; + +/* + * SID for system + */ + +static const char systemsidbytes[] = { + 1, /* revision */ + 1, /* auth count */ + 0, 0, 0, 0, 0, 5, /* base */ + 18, 0, 0, 0 /* 1st level */ + }; + +static const SID *systemsid = (const SID*)systemsidbytes; + +/* + * SID for generic creator-owner + * S-1-3-0 + */ + +static const char ownersidbytes[] = { + 1, /* revision */ + 1, /* auth count */ + 0, 0, 0, 0, 0, 3, /* base */ + 0, 0, 0, 0 /* 1st level */ +} ; + +static const SID *ownersid = (const SID*)ownersidbytes; + +/* + * SID for generic creator-group + * S-1-3-1 + */ + +static const char groupsidbytes[] = { + 1, /* revision */ + 1, /* auth count */ + 0, 0, 0, 0, 0, 3, /* base */ + 1, 0, 0, 0 /* 1st level */ +} ; + +static const SID *groupsid = (const SID*)groupsidbytes; + +/* + * Determine the size of a SID + */ + +int ntfs_sid_size(const SID * sid) +{ + return (sid->sub_authority_count * 4 + 8); +} + +/* + * Test whether two SID are equal + */ + +BOOL ntfs_same_sid(const SID *first, const SID *second) +{ + int size; + + size = ntfs_sid_size(first); + return ((ntfs_sid_size(second) == size) + && !memcmp(first, second, size)); +} + +/* + * Test whether a SID means "world user" + * Local users group also recognized as world + */ + +static int is_world_sid(const SID * usid) +{ + return ( + /* check whether S-1-1-0 : world */ + ((usid->sub_authority_count == 1) + && (usid->identifier_authority.high_part == const_cpu_to_be16(0)) + && (usid->identifier_authority.low_part == const_cpu_to_be32(1)) + && (usid->sub_authority[0] == const_cpu_to_le32(0))) + + /* check whether S-1-5-32-545 : local user */ + || ((usid->sub_authority_count == 2) + && (usid->identifier_authority.high_part == const_cpu_to_be16(0)) + && (usid->identifier_authority.low_part == const_cpu_to_be32(5)) + && (usid->sub_authority[0] == const_cpu_to_le32(32)) + && (usid->sub_authority[1] == const_cpu_to_le32(545))) + ); +} + +/* + * Test whether a SID means "some user (or group)" + * Currently we only check for S-1-5-21... but we should + * probably test for other configurations + */ + +BOOL ntfs_is_user_sid(const SID *usid) +{ + return ((usid->sub_authority_count == 5) + && (usid->identifier_authority.high_part == const_cpu_to_be16(0)) + && (usid->identifier_authority.low_part == const_cpu_to_be32(5)) + && (usid->sub_authority[0] == const_cpu_to_le32(21))); +} + +/* + * Determine the size of a security attribute + * whatever the order of fields + */ + +unsigned int ntfs_attr_size(const char *attr) +{ + const SECURITY_DESCRIPTOR_RELATIVE *phead; + const ACL *pdacl; + const ACL *psacl; + const SID *psid; + unsigned int offdacl; + unsigned int offsacl; + unsigned int offowner; + unsigned int offgroup; + unsigned int endsid; + unsigned int endacl; + unsigned int attrsz; + + phead = (const SECURITY_DESCRIPTOR_RELATIVE*)attr; + /* + * First check group, which is the last field in all descriptors + * we build, and in most descriptors built by Windows + */ + attrsz = sizeof(SECURITY_DESCRIPTOR_RELATIVE); + offgroup = le32_to_cpu(phead->group); + if (offgroup >= attrsz) { + /* find end of GSID */ + psid = (const SID*)&attr[offgroup]; + endsid = offgroup + ntfs_sid_size(psid); + if (endsid > attrsz) attrsz = endsid; + } + offowner = le32_to_cpu(phead->owner); + if (offowner >= attrsz) { + /* find end of USID */ + psid = (const SID*)&attr[offowner]; + endsid = offowner + ntfs_sid_size(psid); + attrsz = endsid; + } + offsacl = le32_to_cpu(phead->sacl); + if (offsacl >= attrsz) { + /* find end of SACL */ + psacl = (const ACL*)&attr[offsacl]; + endacl = offsacl + le16_to_cpu(psacl->size); + if (endacl > attrsz) + attrsz = endacl; + } + + + /* find end of DACL */ + offdacl = le32_to_cpu(phead->dacl); + if (offdacl >= attrsz) { + pdacl = (const ACL*)&attr[offdacl]; + endacl = offdacl + le16_to_cpu(pdacl->size); + if (endacl > attrsz) + attrsz = endacl; + } + return (attrsz); +} + +/* + * Do sanity checks on a SID read from storage + * (just check revision and number of authorities) + */ + +BOOL ntfs_valid_sid(const SID *sid) +{ + return ((sid->revision == SID_REVISION) + && (sid->sub_authority_count >= 1) + && (sid->sub_authority_count <= 8)); +} + +/* + * Check whether a SID is acceptable for an implicit + * mapping pattern. + * It should have been already checked it is a valid user SID. + * + * The last authority reference has to be >= 1000 (Windows usage) + * and <= 0x7fffffff, so that 30 bits from a uid and 30 more bits + * from a gid an be inserted with no overflow. + */ + +BOOL ntfs_valid_pattern(const SID *sid) +{ + int cnt; + u32 auth; + le32 leauth; + + cnt = sid->sub_authority_count; + leauth = sid->sub_authority[cnt-1]; + auth = le32_to_cpu(leauth); + return ((auth >= 1000) && (auth <= 0x7fffffff)); +} + +/* + * Compute the uid or gid associated to a SID + * through an implicit mapping + * + * Returns 0 (root) if it does not match pattern + */ + +static u32 findimplicit(const SID *xsid, const SID *pattern, int parity) +{ + BIGSID defsid; + SID *psid; + u32 xid; /* uid or gid */ + int cnt; + u32 carry; + le32 leauth; + u32 uauth; + u32 xlast; + u32 rlast; + + memcpy(&defsid,pattern,ntfs_sid_size(pattern)); + psid = (SID*)&defsid; + cnt = psid->sub_authority_count; + xid = 0; + if (xsid->sub_authority_count == cnt) { + psid->sub_authority[cnt-1] = xsid->sub_authority[cnt-1]; + leauth = xsid->sub_authority[cnt-1]; + xlast = le32_to_cpu(leauth); + leauth = pattern->sub_authority[cnt-1]; + rlast = le32_to_cpu(leauth); + + if ((xlast > rlast) && !((xlast ^ rlast ^ parity) & 1)) { + /* direct check for basic situation */ + if (ntfs_same_sid(psid,xsid)) + xid = ((xlast - rlast) >> 1) & 0x3fffffff; + else { + /* + * check whether part of mapping had to be + * recorded in a higher level authority + */ + carry = 1; + do { + leauth = psid->sub_authority[cnt-2]; + uauth = le32_to_cpu(leauth) + 1; + psid->sub_authority[cnt-2] + = cpu_to_le32(uauth); + } while (!ntfs_same_sid(psid,xsid) + && (++carry < 4)); + if (carry < 4) + xid = (((xlast - rlast) >> 1) + & 0x3fffffff) | (carry << 30); + } + } + } + return (xid); +} + +/* + * Find usid mapped to a Linux user + * Returns NULL if not found + */ + +const SID *ntfs_find_usid(const struct MAPPING* usermapping, + uid_t uid, SID *defusid) +{ + const struct MAPPING *p; + const SID *sid; + le32 leauth; + u32 uauth; + int cnt; + + if (!uid) + sid = adminsid; + else { + p = usermapping; + while (p && p->xid && ((uid_t)p->xid != uid)) + p = p->next; + if (p && !p->xid) { + /* + * default pattern has been reached : + * build an implicit SID according to pattern + * (the pattern format was checked while reading + * the mapping file) + */ + memcpy(defusid, p->sid, ntfs_sid_size(p->sid)); + cnt = defusid->sub_authority_count; + leauth = defusid->sub_authority[cnt-1]; + uauth = le32_to_cpu(leauth) + 2*(uid & 0x3fffffff); + defusid->sub_authority[cnt-1] = cpu_to_le32(uauth); + if (uid & 0xc0000000) { + leauth = defusid->sub_authority[cnt-2]; + uauth = le32_to_cpu(leauth) + ((uid >> 30) & 3); + defusid->sub_authority[cnt-2] = cpu_to_le32(uauth); + } + sid = defusid; + } else + sid = (p ? p->sid : (const SID*)NULL); + } + return (sid); +} + +/* + * Find Linux group mapped to a gsid + * Returns 0 (root) if not found + */ + +const SID *ntfs_find_gsid(const struct MAPPING* groupmapping, + gid_t gid, SID *defgsid) +{ + const struct MAPPING *p; + const SID *sid; + le32 leauth; + u32 uauth; + int cnt; + + if (!gid) + sid = adminsid; + else { + p = groupmapping; + while (p && p->xid && ((gid_t)p->xid != gid)) + p = p->next; + if (p && !p->xid) { + /* + * default pattern has been reached : + * build an implicit SID according to pattern + * (the pattern format was checked while reading + * the mapping file) + */ + memcpy(defgsid, p->sid, ntfs_sid_size(p->sid)); + cnt = defgsid->sub_authority_count; + leauth = defgsid->sub_authority[cnt-1]; + uauth = le32_to_cpu(leauth) + 2*(gid & 0x3fffffff) + 1; + defgsid->sub_authority[cnt-1] = cpu_to_le32(uauth); + if (gid & 0xc0000000) { + leauth = defgsid->sub_authority[cnt-2]; + uauth = le32_to_cpu(leauth) + ((gid >> 30) & 3); + defgsid->sub_authority[cnt-2] = cpu_to_le32(uauth); + } + sid = defgsid; + } else + sid = (p ? p->sid : (const SID*)NULL); + } + return (sid); +} + +/* + * Find Linux owner mapped to a usid + * Returns 0 (root) if not found + */ + +uid_t ntfs_find_user(const struct MAPPING* usermapping, const SID *usid) +{ + uid_t uid; + const struct MAPPING *p; + + p = usermapping; + while (p && p->xid && !ntfs_same_sid(usid, p->sid)) + p = p->next; + if (p && !p->xid) + /* + * No explicit mapping found, try implicit mapping + */ + uid = findimplicit(usid,p->sid,0); + else + uid = (p ? p->xid : 0); + return (uid); +} + +/* + * Find Linux group mapped to a gsid + * Returns 0 (root) if not found + */ + +gid_t ntfs_find_group(const struct MAPPING* groupmapping, const SID * gsid) +{ + gid_t gid; + const struct MAPPING *p; + int gsidsz; + + gsidsz = ntfs_sid_size(gsid); + p = groupmapping; + while (p && p->xid && !ntfs_same_sid(gsid, p->sid)) + p = p->next; + if (p && !p->xid) + /* + * No explicit mapping found, try implicit mapping + */ + gid = findimplicit(gsid,p->sid,1); + else + gid = (p ? p->xid : 0); + return (gid); +} + +/* + * Check the validity of the ACEs in a DACL or SACL + */ + +static BOOL valid_acl(const ACL *pacl, unsigned int end) +{ + const ACCESS_ALLOWED_ACE *pace; + unsigned int offace; + unsigned int acecnt; + unsigned int acesz; + unsigned int nace; + BOOL ok; + + ok = TRUE; + acecnt = le16_to_cpu(pacl->ace_count); + offace = sizeof(ACL); + for (nace = 0; (nace < acecnt) && ok; nace++) { + /* be sure the beginning is within range */ + if ((offace + sizeof(ACCESS_ALLOWED_ACE)) > end) + ok = FALSE; + else { + pace = (const ACCESS_ALLOWED_ACE*) + &((const char*)pacl)[offace]; + acesz = le16_to_cpu(pace->size); + if (((offace + acesz) > end) + || !ntfs_valid_sid(&pace->sid) + || ((ntfs_sid_size(&pace->sid) + 8) != (int)acesz)) + ok = FALSE; + offace += acesz; + } + } + return (ok); +} + +/* + * Do sanity checks on security descriptors read from storage + * basically, we make sure that every field holds within + * allocated storage + * Should not be called with a NULL argument + * returns TRUE if considered safe + * if not, error should be logged by caller + */ + +BOOL ntfs_valid_descr(const char *securattr, unsigned int attrsz) +{ + const SECURITY_DESCRIPTOR_RELATIVE *phead; + const ACL *pdacl; + const ACL *psacl; + unsigned int offdacl; + unsigned int offsacl; + unsigned int offowner; + unsigned int offgroup; + BOOL ok; + + ok = TRUE; + + /* + * first check overall size if within allocation range + * and a DACL is present + * and owner and group SID are valid + */ + + phead = (const SECURITY_DESCRIPTOR_RELATIVE*)securattr; + offdacl = le32_to_cpu(phead->dacl); + offsacl = le32_to_cpu(phead->sacl); + offowner = le32_to_cpu(phead->owner); + offgroup = le32_to_cpu(phead->group); + pdacl = (const ACL*)&securattr[offdacl]; + psacl = (const ACL*)&securattr[offsacl]; + + /* + * size check occurs before the above pointers are used + * + * "DR Watson" standard directory on WinXP has an + * old revision and no DACL though SE_DACL_PRESENT is set + */ + if ((attrsz >= sizeof(SECURITY_DESCRIPTOR_RELATIVE)) + && (ntfs_attr_size(securattr) <= attrsz) + && (phead->revision == SECURITY_DESCRIPTOR_REVISION) + && (offowner >= sizeof(SECURITY_DESCRIPTOR_RELATIVE)) + && ((offowner + 2) < attrsz) + && (offgroup >= sizeof(SECURITY_DESCRIPTOR_RELATIVE)) + && ((offgroup + 2) < attrsz) + && (!offdacl + || ((offdacl >= sizeof(SECURITY_DESCRIPTOR_RELATIVE)) + && (offdacl < attrsz))) + && (!offsacl + || ((offsacl >= sizeof(SECURITY_DESCRIPTOR_RELATIVE)) + && (offsacl < attrsz))) + && !(phead->owner & const_cpu_to_le32(3)) + && !(phead->group & const_cpu_to_le32(3)) + && !(phead->dacl & const_cpu_to_le32(3)) + && !(phead->sacl & const_cpu_to_le32(3)) + && ntfs_valid_sid((const SID*)&securattr[offowner]) + && ntfs_valid_sid((const SID*)&securattr[offgroup]) + /* + * if there is an ACL, as indicated by offdacl, + * require SE_DACL_PRESENT + * but "Dr Watson" has SE_DACL_PRESENT though no DACL + */ + && (!offdacl + || ((phead->control & SE_DACL_PRESENT) + && ((pdacl->revision == ACL_REVISION) + || (pdacl->revision == ACL_REVISION_DS)))) + /* same for SACL */ + && (!offsacl + || ((phead->control & SE_SACL_PRESENT) + && ((psacl->revision == ACL_REVISION) + || (psacl->revision == ACL_REVISION_DS))))) { + /* + * Check the DACL and SACL if present + */ + if ((offdacl && !valid_acl(pdacl,attrsz - offdacl)) + || (offsacl && !valid_acl(psacl,attrsz - offsacl))) + ok = FALSE; + } else + ok = FALSE; + return (ok); +} + +/* + * Copy the inheritable parts of an ACL + * + * Returns the size of the new ACL + * or zero if nothing is inheritable + */ + +int ntfs_inherit_acl(const ACL *oldacl, ACL *newacl, + const SID *usid, const SID *gsid, BOOL fordir) +{ + unsigned int src; + unsigned int dst; + int oldcnt; + int newcnt; + unsigned int selection; + int nace; + int acesz; + int usidsz; + int gsidsz; + const ACCESS_ALLOWED_ACE *poldace; + ACCESS_ALLOWED_ACE *pnewace; + + usidsz = ntfs_sid_size(usid); + gsidsz = ntfs_sid_size(gsid); + + /* ACL header */ + + newacl->revision = ACL_REVISION; + newacl->alignment1 = 0; + newacl->alignment2 = const_cpu_to_le16(0); + src = dst = sizeof(ACL); + + selection = (fordir ? CONTAINER_INHERIT_ACE : OBJECT_INHERIT_ACE); + newcnt = 0; + oldcnt = le16_to_cpu(oldacl->ace_count); + for (nace = 0; nace < oldcnt; nace++) { + poldace = (const ACCESS_ALLOWED_ACE*)((const char*)oldacl + src); + acesz = le16_to_cpu(poldace->size); + /* inheritance for access */ + if (poldace->flags & selection) { + pnewace = (ACCESS_ALLOWED_ACE*) + ((char*)newacl + dst); + memcpy(pnewace,poldace,acesz); + /* + * Replace generic creator-owner and + * creator-group by owner and group + */ + if (ntfs_same_sid(&pnewace->sid, ownersid)) { + memcpy(&pnewace->sid, usid, usidsz); + acesz = usidsz + 8; + pnewace->size = cpu_to_le16(acesz); + } + if (ntfs_same_sid(&pnewace->sid, groupsid)) { + memcpy(&pnewace->sid, gsid, gsidsz); + acesz = gsidsz + 8; + pnewace->size = cpu_to_le16(acesz); + } + if (pnewace->mask & GENERIC_ALL) { + pnewace->mask &= ~GENERIC_ALL; + if (fordir) + pnewace->mask |= OWNER_RIGHTS + | DIR_READ + | DIR_WRITE + | DIR_EXEC; + else + /* + * The last flag is not defined for a file, + * however Windows sets it, so do the same + */ + pnewace->mask |= OWNER_RIGHTS + | FILE_READ + | FILE_WRITE + | FILE_EXEC + | cpu_to_le32(0x40); + } + /* remove inheritance flags */ + pnewace->flags &= ~(OBJECT_INHERIT_ACE + | CONTAINER_INHERIT_ACE + | INHERIT_ONLY_ACE); + dst += acesz; + newcnt++; + } + /* inheritance for further inheritance */ + if (fordir + && (poldace->flags + & (CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE))) { + pnewace = (ACCESS_ALLOWED_ACE*) + ((char*)newacl + dst); + memcpy(pnewace,poldace,acesz); + /* + * Replace generic creator-owner and + * creator-group by owner and group + */ + if (ntfs_same_sid(&pnewace->sid, ownersid)) { + memcpy(&pnewace->sid, usid, usidsz); + acesz = usidsz + 8; + } + if (ntfs_same_sid(&pnewace->sid, groupsid)) { + memcpy(&pnewace->sid, gsid, gsidsz); + acesz = gsidsz + 8; + } + dst += acesz; + newcnt++; + } + src += acesz; + } + /* + * Adjust header if something was inherited + */ + if (dst > sizeof(ACL)) { + newacl->ace_count = cpu_to_le16(newcnt); + newacl->size = cpu_to_le16(dst); + } else + dst = 0; + return (dst); +} + +#if POSIXACLS + +/* + * Do sanity checks on a Posix descriptor + * Should not be called with a NULL argument + * returns TRUE if considered safe + * if not, error should be logged by caller + */ + +BOOL ntfs_valid_posix(const struct POSIX_SECURITY *pxdesc) +{ + const struct POSIX_ACL *pacl; + int i; + BOOL ok; + u16 tag; + u32 id; + int perms; + struct { + u16 previous; + u32 previousid; + u16 tagsset; + mode_t mode; + int owners; + int groups; + int others; + } checks[2], *pchk; + + for (i=0; i<2; i++) { + checks[i].mode = 0; + checks[i].tagsset = 0; + checks[i].owners = 0; + checks[i].groups = 0; + checks[i].others = 0; + checks[i].previous = 0; + checks[i].previousid = 0; + } + ok = TRUE; + pacl = &pxdesc->acl; + /* + * header (strict for now) + */ + if ((pacl->version != POSIX_VERSION) + || (pacl->flags != 0) + || (pacl->filler != 0)) + ok = FALSE; + /* + * Reject multiple owner, group or other + * but do not require them to be present + * Also check the ACEs are in correct order + * which implies there is no duplicates + */ + for (i=0; iacccnt + pxdesc->defcnt; i++) { + if (i >= pxdesc->firstdef) + pchk = &checks[1]; + else + pchk = &checks[0]; + perms = pacl->ace[i].perms; + tag = pacl->ace[i].tag; + pchk->tagsset |= tag; + id = pacl->ace[i].id; + if (perms & ~7) ok = FALSE; + if ((tag < pchk->previous) + || ((tag == pchk->previous) + && (id <= pchk->previousid))) + ok = FALSE; + pchk->previous = tag; + pchk->previousid = id; + switch (tag) { + case POSIX_ACL_USER_OBJ : + if (pchk->owners++) + ok = FALSE; + if (id != (u32)-1) + ok = FALSE; + pchk->mode |= perms << 6; + break; + case POSIX_ACL_GROUP_OBJ : + if (pchk->groups++) + ok = FALSE; + if (id != (u32)-1) + ok = FALSE; + pchk->mode = (pchk->mode & 07707) | (perms << 3); + break; + case POSIX_ACL_OTHER : + if (pchk->others++) + ok = FALSE; + if (id != (u32)-1) + ok = FALSE; + pchk->mode |= perms; + break; + case POSIX_ACL_USER : + case POSIX_ACL_GROUP : + if (id == (u32)-1) + ok = FALSE; + break; + case POSIX_ACL_MASK : + if (id != (u32)-1) + ok = FALSE; + pchk->mode = (pchk->mode & 07707) | (perms << 3); + break; + default : + ok = FALSE; + break; + } + } + if ((pxdesc->acccnt > 0) + && ((checks[0].owners != 1) || (checks[0].groups != 1) + || (checks[0].others != 1))) + ok = FALSE; + /* do not check owner, group or other are present in */ + /* the default ACL, Windows does not necessarily set them */ + /* descriptor */ + if (pxdesc->defcnt && (pxdesc->acccnt > pxdesc->firstdef)) + ok = FALSE; + if ((pxdesc->acccnt < 0) || (pxdesc->defcnt < 0)) + ok = FALSE; + /* check mode, unless null or no tag set */ + if (pxdesc->mode + && checks[0].tagsset + && (checks[0].mode != (pxdesc->mode & 0777))) + ok = FALSE; + /* check tagsset */ + if (pxdesc->tagsset != checks[0].tagsset) + ok = FALSE; + return (ok); +} + +/* + * Set standard header data into a Posix ACL + * The mode argument should provide the 3 upper bits of target mode + */ + +static mode_t posix_header(struct POSIX_SECURITY *pxdesc, mode_t basemode) +{ + mode_t mode; + u16 tagsset; + struct POSIX_ACE *pace; + int i; + + mode = basemode & 07000; + tagsset = 0; + for (i=0; iacccnt; i++) { + pace = &pxdesc->acl.ace[i]; + tagsset |= pace->tag; + switch(pace->tag) { + case POSIX_ACL_USER_OBJ : + mode |= (pace->perms & 7) << 6; + break; + case POSIX_ACL_GROUP_OBJ : + case POSIX_ACL_MASK : + mode = (mode & 07707) | ((pace->perms & 7) << 3); + break; + case POSIX_ACL_OTHER : + mode |= pace->perms & 7; + break; + default : + break; + } + } + pxdesc->tagsset = tagsset; + pxdesc->mode = mode; + pxdesc->acl.version = POSIX_VERSION; + pxdesc->acl.flags = 0; + pxdesc->acl.filler = 0; + return (mode); +} + +/* + * Sort ACEs in a Posix ACL + * This is useful for always getting reusable converted ACLs, + * it also helps in merging ACEs. + * Repeated tag+id are allowed and not merged here. + * + * Tags should be in ascending sequence and for a repeatable tag + * ids should be in ascending sequence. + */ + +void ntfs_sort_posix(struct POSIX_SECURITY *pxdesc) +{ + struct POSIX_ACL *pacl; + struct POSIX_ACE ace; + int i; + int offs; + BOOL done; + u16 tag; + u16 previous; + u32 id; + u32 previousid; + + + /* + * Check sequencing of tag+id in access ACE's + */ + pacl = &pxdesc->acl; + do { + done = TRUE; + previous = pacl->ace[0].tag; + previousid = pacl->ace[0].id; + for (i=1; iacccnt; i++) { + tag = pacl->ace[i].tag; + id = pacl->ace[i].id; + + if ((tag < previous) + || ((tag == previous) && (id < previousid))) { + done = FALSE; + memcpy(&ace,&pacl->ace[i-1],sizeof(struct POSIX_ACE)); + memcpy(&pacl->ace[i-1],&pacl->ace[i],sizeof(struct POSIX_ACE)); + memcpy(&pacl->ace[i],&ace,sizeof(struct POSIX_ACE)); + } else { + previous = tag; + previousid = id; + } + } + } while (!done); + /* + * Same for default ACEs + */ + do { + done = TRUE; + if ((pxdesc->defcnt) > 1) { + offs = pxdesc->firstdef; + previous = pacl->ace[offs].tag; + previousid = pacl->ace[offs].id; + for (i=offs+1; idefcnt; i++) { + tag = pacl->ace[i].tag; + id = pacl->ace[i].id; + + if ((tag < previous) + || ((tag == previous) && (id < previousid))) { + done = FALSE; + memcpy(&ace,&pacl->ace[i-1],sizeof(struct POSIX_ACE)); + memcpy(&pacl->ace[i-1],&pacl->ace[i],sizeof(struct POSIX_ACE)); + memcpy(&pacl->ace[i],&ace,sizeof(struct POSIX_ACE)); + } else { + previous = tag; + previousid = id; + } + } + } + } while (!done); +} + +/* + * Merge a new mode into a Posix descriptor + * The Posix descriptor is not reallocated, its size is unchanged + * + * returns 0 if ok + */ + +int ntfs_merge_mode_posix(struct POSIX_SECURITY *pxdesc, mode_t mode) +{ + int i; + BOOL maskfound; + struct POSIX_ACE *pace; + int todo; + + maskfound = FALSE; + todo = POSIX_ACL_USER_OBJ | POSIX_ACL_GROUP_OBJ | POSIX_ACL_OTHER; + for (i=pxdesc->acccnt-1; i>=0; i--) { + pace = &pxdesc->acl.ace[i]; + switch(pace->tag) { + case POSIX_ACL_USER_OBJ : + pace->perms = (mode >> 6) & 7; + todo &= ~POSIX_ACL_USER_OBJ; + break; + case POSIX_ACL_GROUP_OBJ : + if (!maskfound) + pace->perms = (mode >> 3) & 7; + todo &= ~POSIX_ACL_GROUP_OBJ; + break; + case POSIX_ACL_MASK : + pace->perms = (mode >> 3) & 7; + maskfound = TRUE; + break; + case POSIX_ACL_OTHER : + pace->perms = mode & 7; + todo &= ~POSIX_ACL_OTHER; + break; + default : + break; + } + } + pxdesc->mode = mode; + return (todo ? -1 : 0); +} + +/* + * Replace an access or default Posix ACL + * The resulting ACL is checked for validity + * + * Returns a new ACL or NULL if there is a problem + */ + +struct POSIX_SECURITY *ntfs_replace_acl(const struct POSIX_SECURITY *oldpxdesc, + const struct POSIX_ACL *newacl, int count, BOOL deflt) +{ + struct POSIX_SECURITY *newpxdesc; + size_t newsize; + int offset; + int oldoffset; + int i; + + if (deflt) + newsize = sizeof(struct POSIX_SECURITY) + + (oldpxdesc->acccnt + count)*sizeof(struct POSIX_ACE); + else + newsize = sizeof(struct POSIX_SECURITY) + + (oldpxdesc->defcnt + count)*sizeof(struct POSIX_ACE); + newpxdesc = (struct POSIX_SECURITY*)malloc(newsize); + if (newpxdesc) { + if (deflt) { + offset = oldpxdesc->acccnt; + newpxdesc->acccnt = oldpxdesc->acccnt; + newpxdesc->defcnt = count; + newpxdesc->firstdef = offset; + /* copy access ACEs */ + for (i=0; iacccnt; i++) + newpxdesc->acl.ace[i] = oldpxdesc->acl.ace[i]; + /* copy default ACEs */ + for (i=0; iacl.ace[i + offset] = newacl->ace[i]; + } else { + offset = count; + newpxdesc->acccnt = count; + newpxdesc->defcnt = oldpxdesc->defcnt; + newpxdesc->firstdef = count; + /* copy access ACEs */ + for (i=0; iacl.ace[i] = newacl->ace[i]; + /* copy default ACEs */ + oldoffset = oldpxdesc->firstdef; + for (i=0; idefcnt; i++) + newpxdesc->acl.ace[i + offset] = oldpxdesc->acl.ace[i + oldoffset]; + } + /* assume special flags unchanged */ + posix_header(newpxdesc, oldpxdesc->mode); + if (!ntfs_valid_posix(newpxdesc)) { + /* do not log, this is an application error */ + free(newpxdesc); + newpxdesc = (struct POSIX_SECURITY*)NULL; + errno = EINVAL; + } + } else + errno = ENOMEM; + return (newpxdesc); +} + +/* + * Build an inherited Posix descriptor from parent + * descriptor (if any) restricted to creation mode + * + * Returns the inherited descriptor or NULL if there is a problem + */ + +struct POSIX_SECURITY *ntfs_build_inherited_posix( + const struct POSIX_SECURITY *pxdesc, mode_t mode, + mode_t mask, BOOL isdir) +{ + struct POSIX_SECURITY *pydesc; + struct POSIX_ACE *pyace; + int count; + int defcnt; + int size; + int i; + s16 tagsset; + + if (pxdesc && pxdesc->defcnt) { + if (isdir) + count = 2*pxdesc->defcnt + 3; + else + count = pxdesc->defcnt + 3; + } else + count = 3; + pydesc = (struct POSIX_SECURITY*)malloc( + sizeof(struct POSIX_SECURITY) + count*sizeof(struct POSIX_ACE)); + if (pydesc) { + /* + * Copy inherited tags and adapt perms + * Use requested mode, ignoring umask + * (not possible with older versions of fuse) + */ + tagsset = 0; + defcnt = (pxdesc ? pxdesc->defcnt : 0); + for (i=defcnt-1; i>=0; i--) { + pyace = &pydesc->acl.ace[i]; + *pyace = pxdesc->acl.ace[pxdesc->firstdef + i]; + switch (pyace->tag) { + case POSIX_ACL_USER_OBJ : + pyace->perms &= (mode >> 6) & 7; + break; + case POSIX_ACL_GROUP_OBJ : + if (!(tagsset & POSIX_ACL_MASK)) + pyace->perms &= (mode >> 3) & 7; + break; + case POSIX_ACL_OTHER : + pyace->perms &= mode & 7; + break; + case POSIX_ACL_MASK : + pyace->perms &= (mode >> 3) & 7; + break; + default : + break; + } + tagsset |= pyace->tag; + } + pydesc->acccnt = defcnt; + /* + * If some standard tags were missing, append them from mode + * and sort the list + * Here we have to use the umask'ed mode + */ + if (~tagsset & (POSIX_ACL_USER_OBJ + | POSIX_ACL_GROUP_OBJ | POSIX_ACL_OTHER)) { + i = defcnt; + /* owner was missing */ + if (!(tagsset & POSIX_ACL_USER_OBJ)) { + pyace = &pydesc->acl.ace[i]; + pyace->tag = POSIX_ACL_USER_OBJ; + pyace->id = -1; + pyace->perms = ((mode & ~mask) >> 6) & 7; + tagsset |= POSIX_ACL_USER_OBJ; + i++; + } + /* owning group was missing */ + if (!(tagsset & POSIX_ACL_GROUP_OBJ)) { + pyace = &pydesc->acl.ace[i]; + pyace->tag = POSIX_ACL_GROUP_OBJ; + pyace->id = -1; + pyace->perms = ((mode & ~mask) >> 3) & 7; + tagsset |= POSIX_ACL_GROUP_OBJ; + i++; + } + /* other was missing */ + if (!(tagsset & POSIX_ACL_OTHER)) { + pyace = &pydesc->acl.ace[i]; + pyace->tag = POSIX_ACL_OTHER; + pyace->id = -1; + pyace->perms = mode & ~mask & 7; + tagsset |= POSIX_ACL_OTHER; + i++; + } + pydesc->acccnt = i; + pydesc->firstdef = i; + pydesc->defcnt = 0; + ntfs_sort_posix(pydesc); + } + + /* + * append as a default ACL if a directory + */ + pydesc->firstdef = pydesc->acccnt; + if (defcnt && isdir) { + size = sizeof(struct POSIX_ACE)*defcnt; + memcpy(&pydesc->acl.ace[pydesc->firstdef], + &pxdesc->acl.ace[pxdesc->firstdef],size); + pydesc->defcnt = defcnt; + } else { + pydesc->defcnt = 0; + } + /* assume special bits are not inherited */ + posix_header(pydesc, mode & 07000); + if (!ntfs_valid_posix(pydesc)) { + ntfs_log_error("Error building an inherited Posix desc\n"); + errno = EIO; + free(pydesc); + pydesc = (struct POSIX_SECURITY*)NULL; + } + } else + errno = ENOMEM; + return (pydesc); +} + +static int merge_lists_posix(struct POSIX_ACE *targetace, + const struct POSIX_ACE *firstace, + const struct POSIX_ACE *secondace, + int firstcnt, int secondcnt) +{ + int k; + + k = 0; + /* + * No list is exhausted : + * if same tag+id in both list : + * ignore ACE from second list + * else take the one with smaller tag+id + */ + while ((firstcnt > 0) && (secondcnt > 0)) + if ((firstace->tag == secondace->tag) + && (firstace->id == secondace->id)) { + secondace++; + secondcnt--; + } else + if ((firstace->tag < secondace->tag) + || ((firstace->tag == secondace->tag) + && (firstace->id < secondace->id))) { + targetace->tag = firstace->tag; + targetace->id = firstace->id; + targetace->perms = firstace->perms; + firstace++; + targetace++; + firstcnt--; + k++; + } else { + targetace->tag = secondace->tag; + targetace->id = secondace->id; + targetace->perms = secondace->perms; + secondace++; + targetace++; + secondcnt--; + k++; + } + /* + * One list is exhausted, copy the other one + */ + while (firstcnt > 0) { + targetace->tag = firstace->tag; + targetace->id = firstace->id; + targetace->perms = firstace->perms; + firstace++; + targetace++; + firstcnt--; + k++; + } + while (secondcnt > 0) { + targetace->tag = secondace->tag; + targetace->id = secondace->id; + targetace->perms = secondace->perms; + secondace++; + targetace++; + secondcnt--; + k++; + } + return (k); +} + +/* + * Merge two Posix ACLs + * The input ACLs have to be adequately sorted + * + * Returns the merged ACL, which is allocated and has to be freed by caller, + * or NULL if failed + */ + +struct POSIX_SECURITY *ntfs_merge_descr_posix(const struct POSIX_SECURITY *first, + const struct POSIX_SECURITY *second) +{ + struct POSIX_SECURITY *pxdesc; + struct POSIX_ACE *targetace; + const struct POSIX_ACE *firstace; + const struct POSIX_ACE *secondace; + size_t size; + int k; + + size = sizeof(struct POSIX_SECURITY) + + (first->acccnt + first->defcnt + + second->acccnt + second->defcnt)*sizeof(struct POSIX_ACE); + pxdesc = (struct POSIX_SECURITY*)malloc(size); + if (pxdesc) { + /* + * merge access ACEs + */ + firstace = first->acl.ace; + secondace = second->acl.ace; + targetace = pxdesc->acl.ace; + k = merge_lists_posix(targetace,firstace,secondace, + first->acccnt,second->acccnt); + pxdesc->acccnt = k; + /* + * merge default ACEs + */ + pxdesc->firstdef = k; + firstace = &first->acl.ace[first->firstdef]; + secondace = &second->acl.ace[second->firstdef]; + targetace = &pxdesc->acl.ace[k]; + k = merge_lists_posix(targetace,firstace,secondace, + first->defcnt,second->defcnt); + pxdesc->defcnt = k; + /* + * build header + */ + pxdesc->acl.version = POSIX_VERSION; + pxdesc->acl.flags = 0; + pxdesc->acl.filler = 0; + pxdesc->mode = 0; + pxdesc->tagsset = 0; + } else + errno = ENOMEM; + return (pxdesc); +} + +struct BUILD_CONTEXT { + BOOL isdir; + BOOL adminowns; + BOOL groupowns; + u16 selfuserperms; + u16 selfgrpperms; + u16 grpperms; + u16 othperms; + u16 mask; + u16 designates; + u16 withmask; + u16 rootspecial; +} ; + + + +static BOOL build_user_denials(ACL *pacl, + const SID *usid, struct MAPPING* const mapping[], + ACE_FLAGS flags, const struct POSIX_ACE *pxace, + struct BUILD_CONTEXT *pset) +{ + BIGSID defsid; + ACCESS_ALLOWED_ACE *pdace; + const SID *sid; + int sidsz; + int pos; + int acecnt; + le32 grants; + le32 denials; + u16 perms; + u16 mixperms; + u16 tag; + BOOL rejected; + BOOL rootuser; + BOOL avoidmask; + + rejected = FALSE; + tag = pxace->tag; + perms = pxace->perms; + rootuser = FALSE; + pos = le16_to_cpu(pacl->size); + acecnt = le16_to_cpu(pacl->ace_count); + avoidmask = (pset->mask == (POSIX_PERM_R | POSIX_PERM_W | POSIX_PERM_X)) + && ((pset->designates && pset->withmask) + || (!pset->designates && !pset->withmask)); + if (tag == POSIX_ACL_USER_OBJ) { + sid = usid; + sidsz = ntfs_sid_size(sid); + grants = OWNER_RIGHTS; + } else { + if (pxace->id) { + sid = NTFS_FIND_USID(mapping[MAPUSERS], + pxace->id, (SID*)&defsid); + grants = WORLD_RIGHTS; + } else { + sid = adminsid; + rootuser = TRUE; + grants = WORLD_RIGHTS & ~ROOT_OWNER_UNMARK; + } + if (sid) { + sidsz = ntfs_sid_size(sid); + /* + * Insert denial of complement of mask for + * each designated user (except root) + * WRITE_OWNER is inserted so that + * the mask can be identified + */ + if (!avoidmask && !rootuser) { + denials = WRITE_OWNER; + pdace = (ACCESS_DENIED_ACE*)&((char*)pacl)[pos]; + if (pset->isdir) { + if (!(pset->mask & POSIX_PERM_X)) + denials |= DIR_EXEC; + if (!(pset->mask & POSIX_PERM_W)) + denials |= DIR_WRITE; + if (!(pset->mask & POSIX_PERM_R)) + denials |= DIR_READ; + } else { + if (!(pset->mask & POSIX_PERM_X)) + denials |= FILE_EXEC; + if (!(pset->mask & POSIX_PERM_W)) + denials |= FILE_WRITE; + if (!(pset->mask & POSIX_PERM_R)) + denials |= FILE_READ; + } + if (rootuser) + grants &= ~ROOT_OWNER_UNMARK; + pdace->type = ACCESS_DENIED_ACE_TYPE; + pdace->flags = flags; + pdace->size = cpu_to_le16(sidsz + 8); + pdace->mask = denials; + memcpy((char*)&pdace->sid, sid, sidsz); + pos += sidsz + 8; + acecnt++; + } + } else + rejected = TRUE; + } + if (!rejected) { + if (pset->isdir) { + if (perms & POSIX_PERM_X) + grants |= DIR_EXEC; + if (perms & POSIX_PERM_W) + grants |= DIR_WRITE; + if (perms & POSIX_PERM_R) + grants |= DIR_READ; + } else { + if (perms & POSIX_PERM_X) + grants |= FILE_EXEC; + if (perms & POSIX_PERM_W) + grants |= FILE_WRITE; + if (perms & POSIX_PERM_R) + grants |= FILE_READ; + } + + /* a possible ACE to deny owner what he/she would */ + /* induely get from administrator, group or world */ + /* unless owner is administrator or group */ + + denials = const_cpu_to_le32(0); + pdace = (ACCESS_DENIED_ACE*)&((char*)pacl)[pos]; + if (!pset->adminowns && !rootuser) { + if (!pset->groupowns) { + mixperms = pset->grpperms | pset->othperms; + if (tag == POSIX_ACL_USER_OBJ) + mixperms |= pset->selfuserperms; + if (pset->isdir) { + if (mixperms & POSIX_PERM_X) + denials |= DIR_EXEC; + if (mixperms & POSIX_PERM_W) + denials |= DIR_WRITE; + if (mixperms & POSIX_PERM_R) + denials |= DIR_READ; + } else { + if (mixperms & POSIX_PERM_X) + denials |= FILE_EXEC; + if (mixperms & POSIX_PERM_W) + denials |= FILE_WRITE; + if (mixperms & POSIX_PERM_R) + denials |= FILE_READ; + } + } else { + mixperms = ~pset->grpperms & pset->othperms; + if (tag == POSIX_ACL_USER_OBJ) + mixperms |= pset->selfuserperms; + if (pset->isdir) { + if (mixperms & POSIX_PERM_X) + denials |= DIR_EXEC; + if (mixperms & POSIX_PERM_W) + denials |= DIR_WRITE; + if (mixperms & POSIX_PERM_R) + denials |= DIR_READ; + } else { + if (mixperms & POSIX_PERM_X) + denials |= FILE_EXEC; + if (mixperms & POSIX_PERM_W) + denials |= FILE_WRITE; + if (mixperms & POSIX_PERM_R) + denials |= FILE_READ; + } + } + denials &= ~grants; + if (denials) { + pdace->type = ACCESS_DENIED_ACE_TYPE; + pdace->flags = flags; + pdace->size = cpu_to_le16(sidsz + 8); + pdace->mask = denials; + memcpy((char*)&pdace->sid, sid, sidsz); + pos += sidsz + 8; + acecnt++; + } + } + } + pacl->size = cpu_to_le16(pos); + pacl->ace_count = cpu_to_le16(acecnt); + return (!rejected); +} + +static BOOL build_user_grants(ACL *pacl, + const SID *usid, struct MAPPING* const mapping[], + ACE_FLAGS flags, const struct POSIX_ACE *pxace, + struct BUILD_CONTEXT *pset) +{ + BIGSID defsid; + ACCESS_ALLOWED_ACE *pgace; + const SID *sid; + int sidsz; + int pos; + int acecnt; + le32 grants; + u16 perms; + u16 tag; + BOOL rejected; + BOOL rootuser; + + rejected = FALSE; + tag = pxace->tag; + perms = pxace->perms; + rootuser = FALSE; + pos = le16_to_cpu(pacl->size); + acecnt = le16_to_cpu(pacl->ace_count); + if (tag == POSIX_ACL_USER_OBJ) { + sid = usid; + sidsz = ntfs_sid_size(sid); + grants = OWNER_RIGHTS; + } else { + if (pxace->id) { + sid = NTFS_FIND_USID(mapping[MAPUSERS], + pxace->id, (SID*)&defsid); + if (sid) + sidsz = ntfs_sid_size(sid); + else + rejected = TRUE; + grants = WORLD_RIGHTS; + } else { + sid = adminsid; + sidsz = ntfs_sid_size(sid); + rootuser = TRUE; + grants = WORLD_RIGHTS & ~ROOT_OWNER_UNMARK; + } + } + if (!rejected) { + if (pset->isdir) { + if (perms & POSIX_PERM_X) + grants |= DIR_EXEC; + if (perms & POSIX_PERM_W) + grants |= DIR_WRITE; + if (perms & POSIX_PERM_R) + grants |= DIR_READ; + } else { + if (perms & POSIX_PERM_X) + grants |= FILE_EXEC; + if (perms & POSIX_PERM_W) + grants |= FILE_WRITE; + if (perms & POSIX_PERM_R) + grants |= FILE_READ; + } + if (rootuser) + grants &= ~ROOT_OWNER_UNMARK; + pgace = (ACCESS_DENIED_ACE*)&((char*)pacl)[pos]; + pgace->type = ACCESS_ALLOWED_ACE_TYPE; + pgace->size = cpu_to_le16(sidsz + 8); + pgace->flags = flags; + pgace->mask = grants; + memcpy((char*)&pgace->sid, sid, sidsz); + pos += sidsz + 8; + acecnt = le16_to_cpu(pacl->ace_count) + 1; + pacl->ace_count = cpu_to_le16(acecnt); + pacl->size = cpu_to_le16(pos); + } + return (!rejected); +} + + + /* a grant ACE for group */ + /* unless group-obj has the same rights as world */ + /* but present if group is owner or owner is administrator */ + /* this ACE will be inserted after denials for group */ + +static BOOL build_group_denials_grant(ACL *pacl, + const SID *gsid, struct MAPPING* const mapping[], + ACE_FLAGS flags, const struct POSIX_ACE *pxace, + struct BUILD_CONTEXT *pset) +{ + BIGSID defsid; + ACCESS_ALLOWED_ACE *pdace; + ACCESS_ALLOWED_ACE *pgace; + const SID *sid; + int sidsz; + int pos; + int acecnt; + le32 grants; + le32 denials; + u16 perms; + u16 mixperms; + u16 tag; + BOOL avoidmask; + BOOL rootgroup; + BOOL rejected; + + rejected = FALSE; + tag = pxace->tag; + perms = pxace->perms; + pos = le16_to_cpu(pacl->size); + acecnt = le16_to_cpu(pacl->ace_count); + rootgroup = FALSE; + avoidmask = (pset->mask == (POSIX_PERM_R | POSIX_PERM_W | POSIX_PERM_X)) + && ((pset->designates && pset->withmask) + || (!pset->designates && !pset->withmask)); + if (tag == POSIX_ACL_GROUP_OBJ) + sid = gsid; + else + if (pxace->id) + sid = NTFS_FIND_GSID(mapping[MAPGROUPS], + pxace->id, (SID*)&defsid); + else { + sid = adminsid; + rootgroup = TRUE; + } + if (sid) { + sidsz = ntfs_sid_size(sid); + /* + * Insert denial of complement of mask for + * each group + * WRITE_OWNER is inserted so that + * the mask can be identified + * Note : this mask may lead on Windows to + * deny rights to administrators belonging + * to some user group + */ + if ((!avoidmask && !rootgroup) + || (pset->rootspecial + && (tag == POSIX_ACL_GROUP_OBJ))) { + denials = WRITE_OWNER; + pdace = (ACCESS_DENIED_ACE*)&((char*)pacl)[pos]; + if (pset->isdir) { + if (!(pset->mask & POSIX_PERM_X)) + denials |= DIR_EXEC; + if (!(pset->mask & POSIX_PERM_W)) + denials |= DIR_WRITE; + if (!(pset->mask & POSIX_PERM_R)) + denials |= DIR_READ; + } else { + if (!(pset->mask & POSIX_PERM_X)) + denials |= FILE_EXEC; + if (!(pset->mask & POSIX_PERM_W)) + denials |= FILE_WRITE; + if (!(pset->mask & POSIX_PERM_R)) + denials |= FILE_READ; + } + pdace->type = ACCESS_DENIED_ACE_TYPE; + pdace->flags = flags; + pdace->size = cpu_to_le16(sidsz + 8); + pdace->mask = denials; + memcpy((char*)&pdace->sid, sid, sidsz); + pos += sidsz + 8; + acecnt++; + } + } else + rejected = TRUE; + if (!rejected + && (pset->adminowns + || pset->groupowns + || avoidmask + || rootgroup + || (perms != pset->othperms))) { + grants = WORLD_RIGHTS; + if (rootgroup) + grants &= ~ROOT_GROUP_UNMARK; + if (pset->isdir) { + if (perms & POSIX_PERM_X) + grants |= DIR_EXEC; + if (perms & POSIX_PERM_W) + grants |= DIR_WRITE; + if (perms & POSIX_PERM_R) + grants |= DIR_READ; + } else { + if (perms & POSIX_PERM_X) + grants |= FILE_EXEC; + if (perms & POSIX_PERM_W) + grants |= FILE_WRITE; + if (perms & POSIX_PERM_R) + grants |= FILE_READ; + } + + /* a possible ACE to deny group what it would get from world */ + /* or administrator, unless owner is administrator or group */ + + denials = const_cpu_to_le32(0); + pdace = (ACCESS_DENIED_ACE*)&((char*)pacl)[pos]; + if (!pset->adminowns + && !pset->groupowns + && !rootgroup) { + mixperms = pset->othperms; + if (tag == POSIX_ACL_GROUP_OBJ) + mixperms |= pset->selfgrpperms; + if (pset->isdir) { + if (mixperms & POSIX_PERM_X) + denials |= DIR_EXEC; + if (mixperms & POSIX_PERM_W) + denials |= DIR_WRITE; + if (mixperms & POSIX_PERM_R) + denials |= DIR_READ; + } else { + if (mixperms & POSIX_PERM_X) + denials |= FILE_EXEC; + if (mixperms & POSIX_PERM_W) + denials |= FILE_WRITE; + if (mixperms & POSIX_PERM_R) + denials |= FILE_READ; + } + denials &= ~(grants | OWNER_RIGHTS); + if (denials) { + pdace->type = ACCESS_DENIED_ACE_TYPE; + pdace->flags = flags; + pdace->size = cpu_to_le16(sidsz + 8); + pdace->mask = denials; + memcpy((char*)&pdace->sid, sid, sidsz); + pos += sidsz + 8; + acecnt++; + } + } + + /* now insert grants to group if more than world */ + if (pset->adminowns + || pset->groupowns + || (avoidmask && (pset->designates || pset->withmask)) + || (perms & ~pset->othperms) + || (pset->rootspecial + && (tag == POSIX_ACL_GROUP_OBJ)) + || (tag == POSIX_ACL_GROUP)) { + if (rootgroup) + grants &= ~ROOT_GROUP_UNMARK; + pgace = (ACCESS_DENIED_ACE*)&((char*)pacl)[pos]; + pgace->type = ACCESS_ALLOWED_ACE_TYPE; + pgace->flags = flags; + pgace->size = cpu_to_le16(sidsz + 8); + pgace->mask = grants; + memcpy((char*)&pgace->sid, sid, sidsz); + pos += sidsz + 8; + acecnt++; + } + } + pacl->size = cpu_to_le16(pos); + pacl->ace_count = cpu_to_le16(acecnt); + return (!rejected); +} + + +/* + * Build an ACL composed of several ACE's + * returns size of ACL or zero if failed + * + * Three schemes are defined : + * + * 1) if root is neither owner nor group up to 7 ACE's are set up : + * - denials to owner (preventing grants to world or group to apply) + * + mask denials to designated user (unless mask allows all) + * + denials to designated user + * - grants to owner (always present - first grant) + * + grants to designated user + * + mask denial to group (unless mask allows all) + * - denials to group (preventing grants to world to apply) + * - grants to group (unless group has no more than world rights) + * + mask denials to designated group (unless mask allows all) + * + grants to designated group + * + denials to designated group + * - grants to world (unless none) + * - full privileges to administrator, always present + * - full privileges to system, always present + * + * The same scheme is applied for Posix ACLs, with the mask represented + * as denials prepended to grants for designated users and groups + * + * This is inspired by an Internet Draft from Marius Aamodt Eriksen + * for mapping NFSv4 ACLs to Posix ACLs (draft-ietf-nfsv4-acl-mapping-00.txt) + * More recent versions of the draft (draft-ietf-nfsv4-acl-mapping-05.txt) + * are not followed, as they ignore the Posix mask and lead to + * loss of compatibility with Linux implementations on other fs. + * + * Note that denials to group are located after grants to owner. + * This only occurs in the unfrequent situation where world + * has more rights than group and cannot be avoided if owner and other + * have some common right which is denied to group (eg for mode 745 + * executing has to be denied to group, but not to owner or world). + * This rare situation is processed by Windows correctly, but + * Windows utilities may want to change the order, with a + * consequence of applying the group denials to the Windows owner. + * The interpretation on Linux is not affected by the order change. + * + * 2) if root is either owner or group, two problems arise : + * - granting full rights to administrator (as needed to transpose + * to Windows rights bypassing granting to root) would imply + * Linux permissions to always be seen as rwx, no matter the chmod + * - there is no different SID to separate an administrator owner + * from an administrator group. Hence Linux permissions for owner + * would always be similar to permissions to group. + * + * as a work-around, up to 5 ACE's are set up if owner or group : + * - grants to owner, always present at first position + * - grants to group, always present + * - grants to world, unless none + * - full privileges to administrator, always present + * - full privileges to system, always present + * + * On Windows, these ACE's are processed normally, though they + * are redundant (owner, group and administrator are the same, + * as a consequence any denials would damage administrator rights) + * but on Linux, privileges to administrator are ignored (they + * are not needed as root has always full privileges), and + * neither grants to group are applied to owner, nor grants to + * world are applied to owner or group. + * + * 3) finally a similar situation arises when group is owner (they + * have the same SID), but is not root. + * In this situation up to 6 ACE's are set up : + * + * - denials to owner (preventing grants to world to apply) + * - grants to owner (always present) + * - grants to group (unless groups has same rights as world) + * - grants to world (unless none) + * - full privileges to administrator, always present + * - full privileges to system, always present + * + * On Windows, these ACE's are processed normally, though they + * are redundant (as owner and group are the same), but this has + * no impact on administrator rights + * + * Special flags (S_ISVTX, S_ISGID, S_ISUID) : + * an extra null ACE is inserted to hold these flags, using + * the same conventions as cygwin. + * + */ + +static int buildacls_posix(struct MAPPING* const mapping[], + char *secattr, int offs, const struct POSIX_SECURITY *pxdesc, + int isdir, const SID *usid, const SID *gsid) +{ + struct BUILD_CONTEXT aceset[2], *pset; + BOOL adminowns; + BOOL groupowns; + ACL *pacl; + ACCESS_ALLOWED_ACE *pgace; + ACCESS_ALLOWED_ACE *pdace; + const struct POSIX_ACE *pxace; + BOOL ok; + mode_t mode; + u16 tag; + u16 perms; + ACE_FLAGS flags; + int pos; + int i; + int k; + BIGSID defsid; + const SID *sid; + int acecnt; + int usidsz; + int gsidsz; + int wsidsz; + int asidsz; + int ssidsz; + int nsidsz; + le32 grants; + + usidsz = ntfs_sid_size(usid); + gsidsz = ntfs_sid_size(gsid); + wsidsz = ntfs_sid_size(worldsid); + asidsz = ntfs_sid_size(adminsid); + ssidsz = ntfs_sid_size(systemsid); + mode = pxdesc->mode; + /* adminowns and groupowns are used for both lists */ + adminowns = ntfs_same_sid(usid, adminsid) + || ntfs_same_sid(gsid, adminsid); + groupowns = !adminowns && ntfs_same_sid(usid, gsid); + + ok = TRUE; + + /* ACL header */ + pacl = (ACL*)&secattr[offs]; + pacl->revision = ACL_REVISION; + pacl->alignment1 = 0; + pacl->size = cpu_to_le16(sizeof(ACL) + usidsz + 8); + pacl->ace_count = const_cpu_to_le16(0); + pacl->alignment2 = const_cpu_to_le16(0); + + /* + * Determine what is allowed to some group or world + * to prevent designated users or other groups to get + * rights from groups or world + * Do the same if owner and group appear as designated + * user or group + * Also get global mask + */ + for (k=0; k<2; k++) { + pset = &aceset[k]; + pset->selfuserperms = 0; + pset->selfgrpperms = 0; + pset->grpperms = 0; + pset->othperms = 0; + pset->mask = (POSIX_PERM_R | POSIX_PERM_W | POSIX_PERM_X); + pset->designates = 0; + pset->withmask = 0; + pset->rootspecial = 0; + pset->adminowns = adminowns; + pset->groupowns = groupowns; + pset->isdir = isdir; + } + + for (i=pxdesc->acccnt+pxdesc->defcnt-1; i>=0; i--) { + if (i >= pxdesc->acccnt) { + pset = &aceset[1]; + pxace = &pxdesc->acl.ace[i + pxdesc->firstdef - pxdesc->acccnt]; + } else { + pset = &aceset[0]; + pxace = &pxdesc->acl.ace[i]; + } + switch (pxace->tag) { + case POSIX_ACL_USER : + pset->designates++; + if (pxace->id) { + sid = NTFS_FIND_USID(mapping[MAPUSERS], + pxace->id, (SID*)&defsid); + if (sid && ntfs_same_sid(sid,usid)) + pset->selfuserperms |= pxace->perms; + } else + /* root as designated user is processed apart */ + pset->rootspecial = TRUE; + break; + case POSIX_ACL_GROUP : + pset->designates++; + if (pxace->id) { + sid = NTFS_FIND_GSID(mapping[MAPUSERS], + pxace->id, (SID*)&defsid); + if (sid && ntfs_same_sid(sid,gsid)) + pset->selfgrpperms |= pxace->perms; + } else + /* root as designated group is processed apart */ + pset->rootspecial = TRUE; + /* fall through */ + case POSIX_ACL_GROUP_OBJ : + pset->grpperms |= pxace->perms; + break; + case POSIX_ACL_OTHER : + pset->othperms = pxace->perms; + break; + case POSIX_ACL_MASK : + pset->withmask++; + pset->mask = pxace->perms; + default : + break; + } + } + +if (pxdesc->defcnt && (pxdesc->firstdef != pxdesc->acccnt)) { +ntfs_log_error("** error : access and default not consecutive\n"); +return (0); +} + /* + * First insert all denials for owner and each + * designated user (with mask if needed) + */ + + pacl->ace_count = const_cpu_to_le16(0); + pacl->size = const_cpu_to_le16(sizeof(ACL)); + for (i=0; (i<(pxdesc->acccnt + pxdesc->defcnt)) && ok; i++) { + if (i >= pxdesc->acccnt) { + flags = INHERIT_ONLY_ACE + | OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE; + pset = &aceset[1]; + pxace = &pxdesc->acl.ace[i + pxdesc->firstdef - pxdesc->acccnt]; + } else { + if (pxdesc->defcnt) + flags = NO_PROPAGATE_INHERIT_ACE; + else + flags = (isdir ? DIR_INHERITANCE + : FILE_INHERITANCE); + pset = &aceset[0]; + pxace = &pxdesc->acl.ace[i]; + } + tag = pxace->tag; + perms = pxace->perms; + switch (tag) { + + /* insert denial ACEs for each owner or allowed user */ + + case POSIX_ACL_USER : + case POSIX_ACL_USER_OBJ : + + ok = build_user_denials(pacl, + usid, mapping, flags, pxace, pset); + break; + default : + break; + } + } + + /* + * for directories, insert a world execution denial + * inherited to plain files. + * This is to prevent Windows from granting execution + * of files through inheritance from parent directory + */ + + if (isdir && ok) { + pos = le16_to_cpu(pacl->size); + pdace = (ACCESS_DENIED_ACE*) &secattr[offs + pos]; + pdace->type = ACCESS_DENIED_ACE_TYPE; + pdace->flags = INHERIT_ONLY_ACE | OBJECT_INHERIT_ACE; + pdace->size = cpu_to_le16(wsidsz + 8); + pdace->mask = FILE_EXEC; + memcpy((char*)&pdace->sid, worldsid, wsidsz); + pos += wsidsz + 8; + acecnt = le16_to_cpu(pacl->ace_count) + 1; + pacl->ace_count = cpu_to_le16(acecnt); + pacl->size = cpu_to_le16(pos); + } + + /* + * now insert (if needed) + * - grants to owner and designated users + * - mask and denials for all groups + * - grants to other + */ + + for (i=0; (i<(pxdesc->acccnt + pxdesc->defcnt)) && ok; i++) { + if (i >= pxdesc->acccnt) { + flags = INHERIT_ONLY_ACE + | OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE; + pset = &aceset[1]; + pxace = &pxdesc->acl.ace[i + pxdesc->firstdef - pxdesc->acccnt]; + } else { + if (pxdesc->defcnt) + flags = NO_PROPAGATE_INHERIT_ACE; + else + flags = (isdir ? DIR_INHERITANCE + : FILE_INHERITANCE); + pset = &aceset[0]; + pxace = &pxdesc->acl.ace[i]; + } + tag = pxace->tag; + perms = pxace->perms; + switch (tag) { + + /* ACE for each owner or allowed user */ + + case POSIX_ACL_USER : + case POSIX_ACL_USER_OBJ : + ok = build_user_grants(pacl,usid, + mapping,flags,pxace,pset); + break; + + case POSIX_ACL_GROUP : + case POSIX_ACL_GROUP_OBJ : + + /* denials and grants for groups */ + + ok = build_group_denials_grant(pacl,gsid, + mapping,flags,pxace,pset); + break; + + case POSIX_ACL_OTHER : + + /* grants for other users */ + + pos = le16_to_cpu(pacl->size); + pgace = (ACCESS_ALLOWED_ACE*)&secattr[offs + pos]; + grants = WORLD_RIGHTS; + if (isdir) { + if (perms & POSIX_PERM_X) + grants |= DIR_EXEC; + if (perms & POSIX_PERM_W) + grants |= DIR_WRITE; + if (perms & POSIX_PERM_R) + grants |= DIR_READ; + } else { + if (perms & POSIX_PERM_X) + grants |= FILE_EXEC; + if (perms & POSIX_PERM_W) + grants |= FILE_WRITE; + if (perms & POSIX_PERM_R) + grants |= FILE_READ; + } + pgace->type = ACCESS_ALLOWED_ACE_TYPE; + pgace->flags = flags; + pgace->size = cpu_to_le16(wsidsz + 8); + pgace->mask = grants; + memcpy((char*)&pgace->sid, worldsid, wsidsz); + pos += wsidsz + 8; + acecnt = le16_to_cpu(pacl->ace_count) + 1; + pacl->ace_count = cpu_to_le16(acecnt); + pacl->size = cpu_to_le16(pos); + break; + } + } + + if (!ok) { + errno = EINVAL; + pos = 0; + } else { + /* an ACE for administrators */ + /* always full access */ + + pos = le16_to_cpu(pacl->size); + acecnt = le16_to_cpu(pacl->ace_count); + if (isdir) + flags = OBJECT_INHERIT_ACE + | CONTAINER_INHERIT_ACE; + else + flags = NO_PROPAGATE_INHERIT_ACE; + pgace = (ACCESS_ALLOWED_ACE*)&secattr[offs + pos]; + pgace->type = ACCESS_ALLOWED_ACE_TYPE; + pgace->flags = flags; + pgace->size = cpu_to_le16(asidsz + 8); + grants = OWNER_RIGHTS | FILE_READ | FILE_WRITE | FILE_EXEC; + pgace->mask = grants; + memcpy((char*)&pgace->sid, adminsid, asidsz); + pos += asidsz + 8; + acecnt++; + + /* an ACE for system (needed ?) */ + /* always full access */ + + pgace = (ACCESS_ALLOWED_ACE*)&secattr[offs + pos]; + pgace->type = ACCESS_ALLOWED_ACE_TYPE; + pgace->flags = flags; + pgace->size = cpu_to_le16(ssidsz + 8); + grants = OWNER_RIGHTS | FILE_READ | FILE_WRITE | FILE_EXEC; + pgace->mask = grants; + memcpy((char*)&pgace->sid, systemsid, ssidsz); + pos += ssidsz + 8; + acecnt++; + + /* a null ACE to hold special flags */ + /* using the same representation as cygwin */ + + if (mode & (S_ISVTX | S_ISGID | S_ISUID)) { + nsidsz = ntfs_sid_size(nullsid); + pgace = (ACCESS_ALLOWED_ACE*)&secattr[offs + pos]; + pgace->type = ACCESS_ALLOWED_ACE_TYPE; + pgace->flags = NO_PROPAGATE_INHERIT_ACE; + pgace->size = cpu_to_le16(nsidsz + 8); + grants = const_cpu_to_le32(0); + if (mode & S_ISUID) + grants |= FILE_APPEND_DATA; + if (mode & S_ISGID) + grants |= FILE_WRITE_DATA; + if (mode & S_ISVTX) + grants |= FILE_READ_DATA; + pgace->mask = grants; + memcpy((char*)&pgace->sid, nullsid, nsidsz); + pos += nsidsz + 8; + acecnt++; + } + + /* fix ACL header */ + pacl->size = cpu_to_le16(pos); + pacl->ace_count = cpu_to_le16(acecnt); + } + return (ok ? pos : 0); +} + +#endif /* POSIXACLS */ + +static int buildacls(char *secattr, int offs, mode_t mode, int isdir, + const SID * usid, const SID * gsid) +{ + ACL *pacl; + ACCESS_ALLOWED_ACE *pgace; + ACCESS_ALLOWED_ACE *pdace; + BOOL adminowns; + BOOL groupowns; + ACE_FLAGS gflags; + int pos; + int acecnt; + int usidsz; + int gsidsz; + int wsidsz; + int asidsz; + int ssidsz; + int nsidsz; + le32 grants; + le32 denials; + + usidsz = ntfs_sid_size(usid); + gsidsz = ntfs_sid_size(gsid); + wsidsz = ntfs_sid_size(worldsid); + asidsz = ntfs_sid_size(adminsid); + ssidsz = ntfs_sid_size(systemsid); + adminowns = ntfs_same_sid(usid, adminsid) + || ntfs_same_sid(gsid, adminsid); + groupowns = !adminowns && ntfs_same_sid(usid, gsid); + + /* ACL header */ + pacl = (ACL*)&secattr[offs]; + pacl->revision = ACL_REVISION; + pacl->alignment1 = 0; + pacl->size = cpu_to_le16(sizeof(ACL) + usidsz + 8); + pacl->ace_count = const_cpu_to_le16(1); + pacl->alignment2 = const_cpu_to_le16(0); + pos = sizeof(ACL); + acecnt = 0; + + /* compute a grant ACE for owner */ + /* this ACE will be inserted after denial for owner */ + + grants = OWNER_RIGHTS; + if (isdir) { + gflags = DIR_INHERITANCE; + if (mode & S_IXUSR) + grants |= DIR_EXEC; + if (mode & S_IWUSR) + grants |= DIR_WRITE; + if (mode & S_IRUSR) + grants |= DIR_READ; + } else { + gflags = FILE_INHERITANCE; + if (mode & S_IXUSR) + grants |= FILE_EXEC; + if (mode & S_IWUSR) + grants |= FILE_WRITE; + if (mode & S_IRUSR) + grants |= FILE_READ; + } + + /* a possible ACE to deny owner what he/she would */ + /* induely get from administrator, group or world */ + /* unless owner is administrator or group */ + + denials = const_cpu_to_le32(0); + pdace = (ACCESS_DENIED_ACE*) &secattr[offs + pos]; + if (!adminowns) { + if (!groupowns) { + if (isdir) { + pdace->flags = DIR_INHERITANCE; + if (mode & (S_IXGRP | S_IXOTH)) + denials |= DIR_EXEC; + if (mode & (S_IWGRP | S_IWOTH)) + denials |= DIR_WRITE; + if (mode & (S_IRGRP | S_IROTH)) + denials |= DIR_READ; + } else { + pdace->flags = FILE_INHERITANCE; + if (mode & (S_IXGRP | S_IXOTH)) + denials |= FILE_EXEC; + if (mode & (S_IWGRP | S_IWOTH)) + denials |= FILE_WRITE; + if (mode & (S_IRGRP | S_IROTH)) + denials |= FILE_READ; + } + } else { + if (isdir) { + pdace->flags = DIR_INHERITANCE; + if ((mode & S_IXOTH) && !(mode & S_IXGRP)) + denials |= DIR_EXEC; + if ((mode & S_IWOTH) && !(mode & S_IWGRP)) + denials |= DIR_WRITE; + if ((mode & S_IROTH) && !(mode & S_IRGRP)) + denials |= DIR_READ; + } else { + pdace->flags = FILE_INHERITANCE; + if ((mode & S_IXOTH) && !(mode & S_IXGRP)) + denials |= FILE_EXEC; + if ((mode & S_IWOTH) && !(mode & S_IWGRP)) + denials |= FILE_WRITE; + if ((mode & S_IROTH) && !(mode & S_IRGRP)) + denials |= FILE_READ; + } + } + denials &= ~grants; + if (denials) { + pdace->type = ACCESS_DENIED_ACE_TYPE; + pdace->size = cpu_to_le16(usidsz + 8); + pdace->mask = denials; + memcpy((char*)&pdace->sid, usid, usidsz); + pos += usidsz + 8; + acecnt++; + } + } + /* + * for directories, a world execution denial + * inherited to plain files + */ + + if (isdir) { + pdace = (ACCESS_DENIED_ACE*) &secattr[offs + pos]; + pdace->type = ACCESS_DENIED_ACE_TYPE; + pdace->flags = INHERIT_ONLY_ACE | OBJECT_INHERIT_ACE; + pdace->size = cpu_to_le16(wsidsz + 8); + pdace->mask = FILE_EXEC; + memcpy((char*)&pdace->sid, worldsid, wsidsz); + pos += wsidsz + 8; + acecnt++; + } + + + /* now insert grants to owner */ + pgace = (ACCESS_ALLOWED_ACE*) &secattr[offs + pos]; + pgace->type = ACCESS_ALLOWED_ACE_TYPE; + pgace->size = cpu_to_le16(usidsz + 8); + pgace->flags = gflags; + pgace->mask = grants; + memcpy((char*)&pgace->sid, usid, usidsz); + pos += usidsz + 8; + acecnt++; + + /* a grant ACE for group */ + /* unless group has the same rights as world */ + /* but present if group is owner or owner is administrator */ + /* this ACE will be inserted after denials for group */ + + if (adminowns + || groupowns + || (((mode >> 3) ^ mode) & 7)) { + grants = WORLD_RIGHTS; + if (isdir) { + gflags = DIR_INHERITANCE; + if (mode & S_IXGRP) + grants |= DIR_EXEC; + if (mode & S_IWGRP) + grants |= DIR_WRITE; + if (mode & S_IRGRP) + grants |= DIR_READ; + } else { + gflags = FILE_INHERITANCE; + if (mode & S_IXGRP) + grants |= FILE_EXEC; + if (mode & S_IWGRP) + grants |= FILE_WRITE; + if (mode & S_IRGRP) + grants |= FILE_READ; + } + + /* a possible ACE to deny group what it would get from world */ + /* or administrator, unless owner is administrator or group */ + + denials = const_cpu_to_le32(0); + pdace = (ACCESS_ALLOWED_ACE*)&secattr[offs + pos]; + if (!adminowns && !groupowns) { + if (isdir) { + pdace->flags = DIR_INHERITANCE; + if (mode & S_IXOTH) + denials |= DIR_EXEC; + if (mode & S_IWOTH) + denials |= DIR_WRITE; + if (mode & S_IROTH) + denials |= DIR_READ; + } else { + pdace->flags = FILE_INHERITANCE; + if (mode & S_IXOTH) + denials |= FILE_EXEC; + if (mode & S_IWOTH) + denials |= FILE_WRITE; + if (mode & S_IROTH) + denials |= FILE_READ; + } + denials &= ~(grants | OWNER_RIGHTS); + if (denials) { + pdace->type = ACCESS_DENIED_ACE_TYPE; + pdace->size = cpu_to_le16(gsidsz + 8); + pdace->mask = denials; + memcpy((char*)&pdace->sid, gsid, gsidsz); + pos += gsidsz + 8; + acecnt++; + } + } + + if (adminowns + || groupowns + || ((mode >> 3) & ~mode & 7)) { + /* now insert grants to group */ + /* if more rights than other */ + pgace = (ACCESS_ALLOWED_ACE*)&secattr[offs + pos]; + pgace->type = ACCESS_ALLOWED_ACE_TYPE; + pgace->flags = gflags; + pgace->size = cpu_to_le16(gsidsz + 8); + pgace->mask = grants; + memcpy((char*)&pgace->sid, gsid, gsidsz); + pos += gsidsz + 8; + acecnt++; + } + } + + /* an ACE for world users */ + + pgace = (ACCESS_ALLOWED_ACE*)&secattr[offs + pos]; + pgace->type = ACCESS_ALLOWED_ACE_TYPE; + grants = WORLD_RIGHTS; + if (isdir) { + pgace->flags = DIR_INHERITANCE; + if (mode & S_IXOTH) + grants |= DIR_EXEC; + if (mode & S_IWOTH) + grants |= DIR_WRITE; + if (mode & S_IROTH) + grants |= DIR_READ; + } else { + pgace->flags = FILE_INHERITANCE; + if (mode & S_IXOTH) + grants |= FILE_EXEC; + if (mode & S_IWOTH) + grants |= FILE_WRITE; + if (mode & S_IROTH) + grants |= FILE_READ; + } + pgace->size = cpu_to_le16(wsidsz + 8); + pgace->mask = grants; + memcpy((char*)&pgace->sid, worldsid, wsidsz); + pos += wsidsz + 8; + acecnt++; + + /* an ACE for administrators */ + /* always full access */ + + pgace = (ACCESS_ALLOWED_ACE*)&secattr[offs + pos]; + pgace->type = ACCESS_ALLOWED_ACE_TYPE; + if (isdir) + pgace->flags = DIR_INHERITANCE; + else + pgace->flags = FILE_INHERITANCE; + pgace->size = cpu_to_le16(asidsz + 8); + grants = OWNER_RIGHTS | FILE_READ | FILE_WRITE | FILE_EXEC; + pgace->mask = grants; + memcpy((char*)&pgace->sid, adminsid, asidsz); + pos += asidsz + 8; + acecnt++; + + /* an ACE for system (needed ?) */ + /* always full access */ + + pgace = (ACCESS_ALLOWED_ACE*)&secattr[offs + pos]; + pgace->type = ACCESS_ALLOWED_ACE_TYPE; + if (isdir) + pgace->flags = DIR_INHERITANCE; + else + pgace->flags = FILE_INHERITANCE; + pgace->size = cpu_to_le16(ssidsz + 8); + grants = OWNER_RIGHTS | FILE_READ | FILE_WRITE | FILE_EXEC; + pgace->mask = grants; + memcpy((char*)&pgace->sid, systemsid, ssidsz); + pos += ssidsz + 8; + acecnt++; + + /* a null ACE to hold special flags */ + /* using the same representation as cygwin */ + + if (mode & (S_ISVTX | S_ISGID | S_ISUID)) { + nsidsz = ntfs_sid_size(nullsid); + pgace = (ACCESS_ALLOWED_ACE*)&secattr[offs + pos]; + pgace->type = ACCESS_ALLOWED_ACE_TYPE; + pgace->flags = NO_PROPAGATE_INHERIT_ACE; + pgace->size = cpu_to_le16(nsidsz + 8); + grants = const_cpu_to_le32(0); + if (mode & S_ISUID) + grants |= FILE_APPEND_DATA; + if (mode & S_ISGID) + grants |= FILE_WRITE_DATA; + if (mode & S_ISVTX) + grants |= FILE_READ_DATA; + pgace->mask = grants; + memcpy((char*)&pgace->sid, nullsid, nsidsz); + pos += nsidsz + 8; + acecnt++; + } + + /* fix ACL header */ + pacl->size = cpu_to_le16(pos); + pacl->ace_count = cpu_to_le16(acecnt); + return (pos); +} + +#if POSIXACLS + +/* + * Build a full security descriptor from a Posix ACL + * returns descriptor in allocated memory, must free() after use + */ + +char *ntfs_build_descr_posix(struct MAPPING* const mapping[], + struct POSIX_SECURITY *pxdesc, + int isdir, const SID *usid, const SID *gsid) +{ + int newattrsz; + SECURITY_DESCRIPTOR_RELATIVE *pnhead; + char *newattr; + int aclsz; + int usidsz; + int gsidsz; + int wsidsz; + int asidsz; + int ssidsz; + int k; + + usidsz = ntfs_sid_size(usid); + gsidsz = ntfs_sid_size(gsid); + wsidsz = ntfs_sid_size(worldsid); + asidsz = ntfs_sid_size(adminsid); + ssidsz = ntfs_sid_size(systemsid); + + /* allocate enough space for the new security attribute */ + newattrsz = sizeof(SECURITY_DESCRIPTOR_RELATIVE) /* header */ + + usidsz + gsidsz /* usid and gsid */ + + sizeof(ACL) /* acl header */ + + 2*(8 + usidsz) /* two possible ACE for user */ + + 3*(8 + gsidsz) /* three possible ACE for group and mask */ + + 8 + wsidsz /* one ACE for world */ + + 8 + asidsz /* one ACE for admin */ + + 8 + ssidsz; /* one ACE for system */ + if (isdir) /* a world denial for directories */ + newattrsz += 8 + wsidsz; + if (pxdesc->mode & 07000) /* a NULL ACE for special modes */ + newattrsz += 8 + ntfs_sid_size(nullsid); + /* account for non-owning users and groups */ + for (k=0; kacccnt; k++) { + if ((pxdesc->acl.ace[k].tag == POSIX_ACL_USER) + || (pxdesc->acl.ace[k].tag == POSIX_ACL_GROUP)) + newattrsz += 3*40; /* fixme : maximum size */ + } + /* account for default ACE's */ + newattrsz += 2*40*pxdesc->defcnt; /* fixme : maximum size */ + newattr = (char*)ntfs_malloc(newattrsz); + if (newattr) { + /* build the main header part */ + pnhead = (SECURITY_DESCRIPTOR_RELATIVE*)newattr; + pnhead->revision = SECURITY_DESCRIPTOR_REVISION; + pnhead->alignment = 0; + /* + * The flag SE_DACL_PROTECTED prevents the ACL + * to be changed in an inheritance after creation + */ + pnhead->control = SE_DACL_PRESENT | SE_DACL_PROTECTED + | SE_SELF_RELATIVE; + /* + * Windows prefers ACL first, do the same to + * get the same hash value and avoid duplication + */ + /* build permissions */ + aclsz = buildacls_posix(mapping,newattr, + sizeof(SECURITY_DESCRIPTOR_RELATIVE), + pxdesc, isdir, usid, gsid); + if (aclsz && ((int)(sizeof(SECURITY_DESCRIPTOR_RELATIVE) + + aclsz + usidsz + gsidsz) <= newattrsz)) { + /* append usid and gsid */ + memcpy(&newattr[sizeof(SECURITY_DESCRIPTOR_RELATIVE) + + aclsz], usid, usidsz); + memcpy(&newattr[sizeof(SECURITY_DESCRIPTOR_RELATIVE) + + aclsz + usidsz], gsid, gsidsz); + /* positions of ACL, USID and GSID into header */ + pnhead->owner = + cpu_to_le32(sizeof(SECURITY_DESCRIPTOR_RELATIVE) + + aclsz); + pnhead->group = + cpu_to_le32(sizeof(SECURITY_DESCRIPTOR_RELATIVE) + + aclsz + usidsz); + pnhead->sacl = const_cpu_to_le32(0); + pnhead->dacl = + const_cpu_to_le32(sizeof(SECURITY_DESCRIPTOR_RELATIVE)); + } else { + /* ACL failure (errno set) or overflow */ + free(newattr); + newattr = (char*)NULL; + if (aclsz) { + /* hope error was detected before overflowing */ + ntfs_log_error("Security descriptor is longer than expected\n"); + errno = EIO; + } + } + } else + errno = ENOMEM; + return (newattr); +} + +#endif /* POSIXACLS */ + +/* + * Build a full security descriptor + * returns descriptor in allocated memory, must free() after use + */ + +char *ntfs_build_descr(mode_t mode, + int isdir, const SID * usid, const SID * gsid) +{ + int newattrsz; + SECURITY_DESCRIPTOR_RELATIVE *pnhead; + char *newattr; + int aclsz; + int usidsz; + int gsidsz; + int wsidsz; + int asidsz; + int ssidsz; + + usidsz = ntfs_sid_size(usid); + gsidsz = ntfs_sid_size(gsid); + wsidsz = ntfs_sid_size(worldsid); + asidsz = ntfs_sid_size(adminsid); + ssidsz = ntfs_sid_size(systemsid); + + /* allocate enough space for the new security attribute */ + newattrsz = sizeof(SECURITY_DESCRIPTOR_RELATIVE) /* header */ + + usidsz + gsidsz /* usid and gsid */ + + sizeof(ACL) /* acl header */ + + 2*(8 + usidsz) /* two possible ACE for user */ + + 2*(8 + gsidsz) /* two possible ACE for group */ + + 8 + wsidsz /* one ACE for world */ + + 8 + asidsz /* one ACE for admin */ + + 8 + ssidsz; /* one ACE for system */ + if (isdir) /* a world denial for directories */ + newattrsz += 8 + wsidsz; + if (mode & 07000) /* a NULL ACE for special modes */ + newattrsz += 8 + ntfs_sid_size(nullsid); + newattr = (char*)ntfs_malloc(newattrsz); + if (newattr) { + /* build the main header part */ + pnhead = (SECURITY_DESCRIPTOR_RELATIVE*) newattr; + pnhead->revision = SECURITY_DESCRIPTOR_REVISION; + pnhead->alignment = 0; + /* + * The flag SE_DACL_PROTECTED prevents the ACL + * to be changed in an inheritance after creation + */ + pnhead->control = SE_DACL_PRESENT | SE_DACL_PROTECTED + | SE_SELF_RELATIVE; + /* + * Windows prefers ACL first, do the same to + * get the same hash value and avoid duplication + */ + /* build permissions */ + aclsz = buildacls(newattr, + sizeof(SECURITY_DESCRIPTOR_RELATIVE), + mode, isdir, usid, gsid); + if (((int)sizeof(SECURITY_DESCRIPTOR_RELATIVE) + + aclsz + usidsz + gsidsz) <= newattrsz) { + /* append usid and gsid */ + memcpy(&newattr[sizeof(SECURITY_DESCRIPTOR_RELATIVE) + + aclsz], usid, usidsz); + memcpy(&newattr[sizeof(SECURITY_DESCRIPTOR_RELATIVE) + + aclsz + usidsz], gsid, gsidsz); + /* positions of ACL, USID and GSID into header */ + pnhead->owner = + cpu_to_le32(sizeof(SECURITY_DESCRIPTOR_RELATIVE) + + aclsz); + pnhead->group = + cpu_to_le32(sizeof(SECURITY_DESCRIPTOR_RELATIVE) + + aclsz + usidsz); + pnhead->sacl = const_cpu_to_le32(0); + pnhead->dacl = + const_cpu_to_le32(sizeof(SECURITY_DESCRIPTOR_RELATIVE)); + } else { + /* hope error was detected before overflowing */ + free(newattr); + newattr = (char*)NULL; + ntfs_log_error("Security descriptor is longer than expected\n"); + errno = EIO; + } + } else + errno = ENOMEM; + return (newattr); +} + +/* + * Create a mode_t permission set + * from owner, group and world grants as represented in ACEs + */ + +static int merge_permissions(BOOL isdir, + le32 owner, le32 group, le32 world, le32 special) + +{ + int perm; + + perm = 0; + /* build owner permission */ + if (owner) { + if (isdir) { + /* exec if any of list, traverse */ + if (owner & DIR_GEXEC) + perm |= S_IXUSR; + /* write if any of addfile, adddir, delchild */ + if (owner & DIR_GWRITE) + perm |= S_IWUSR; + /* read if any of list */ + if (owner & DIR_GREAD) + perm |= S_IRUSR; + } else { + /* exec if execute or generic execute */ + if (owner & FILE_GEXEC) + perm |= S_IXUSR; + /* write if any of writedata or generic write */ + if (owner & FILE_GWRITE) + perm |= S_IWUSR; + /* read if any of readdata or generic read */ + if (owner & FILE_GREAD) + perm |= S_IRUSR; + } + } + /* build group permission */ + if (group) { + if (isdir) { + /* exec if any of list, traverse */ + if (group & DIR_GEXEC) + perm |= S_IXGRP; + /* write if any of addfile, adddir, delchild */ + if (group & DIR_GWRITE) + perm |= S_IWGRP; + /* read if any of list */ + if (group & DIR_GREAD) + perm |= S_IRGRP; + } else { + /* exec if execute */ + if (group & FILE_GEXEC) + perm |= S_IXGRP; + /* write if any of writedata, appenddata */ + if (group & FILE_GWRITE) + perm |= S_IWGRP; + /* read if any of readdata */ + if (group & FILE_GREAD) + perm |= S_IRGRP; + } + } + /* build world permission */ + if (world) { + if (isdir) { + /* exec if any of list, traverse */ + if (world & DIR_GEXEC) + perm |= S_IXOTH; + /* write if any of addfile, adddir, delchild */ + if (world & DIR_GWRITE) + perm |= S_IWOTH; + /* read if any of list */ + if (world & DIR_GREAD) + perm |= S_IROTH; + } else { + /* exec if execute */ + if (world & FILE_GEXEC) + perm |= S_IXOTH; + /* write if any of writedata, appenddata */ + if (world & FILE_GWRITE) + perm |= S_IWOTH; + /* read if any of readdata */ + if (world & FILE_GREAD) + perm |= S_IROTH; + } + } + /* build special permission flags */ + if (special) { + if (special & FILE_APPEND_DATA) + perm |= S_ISUID; + if (special & FILE_WRITE_DATA) + perm |= S_ISGID; + if (special & FILE_READ_DATA) + perm |= S_ISVTX; + } + return (perm); +} + +#if POSIXACLS + +/* + * Normalize a Posix ACL either from a sorted raw set of + * access ACEs or default ACEs + * (standard case : different owner, group and administrator) + */ + +static int norm_std_permissions_posix(struct POSIX_SECURITY *posix_desc, + BOOL groupowns, int start, int count, int target) +{ + int j,k; + s32 id; + u16 tag; + u16 tagsset; + struct POSIX_ACE *pxace; + mode_t grantgrps; + mode_t grantwrld; + mode_t denywrld; + mode_t allow; + mode_t deny; + mode_t perms; + mode_t mode; + + mode = 0; + tagsset = 0; + /* + * Determine what is granted to some group or world + * Also get denials to world which are meant to prevent + * execution flags to be inherited by plain files + */ + pxace = posix_desc->acl.ace; + grantgrps = 0; + grantwrld = 0; + denywrld = 0; + for (j=start; j<(start + count); j++) { + if (pxace[j].perms & POSIX_PERM_DENIAL) { + /* deny world exec unless for default */ + if ((pxace[j].tag == POSIX_ACL_OTHER) + && !start) + denywrld = pxace[j].perms; + } else { + switch (pxace[j].tag) { + case POSIX_ACL_GROUP_OBJ : + grantgrps |= pxace[j].perms; + break; + case POSIX_ACL_GROUP : + if (pxace[j].id) + grantgrps |= pxace[j].perms; + break; + case POSIX_ACL_OTHER : + grantwrld = pxace[j].perms; + break; + default : + break; + } + } + } + /* + * Collect groups of ACEs related to the same id + * and determine what is granted and what is denied. + * It is important the ACEs have been sorted + */ + j = start; + k = target; + while (j < (start + count)) { + tag = pxace[j].tag; + id = pxace[j].id; + if (pxace[j].perms & POSIX_PERM_DENIAL) { + deny = pxace[j].perms | denywrld; + allow = 0; + } else { + deny = denywrld; + allow = pxace[j].perms; + } + j++; + while ((j < (start + count)) + && (pxace[j].tag == tag) + && (pxace[j].id == id)) { + if (pxace[j].perms & POSIX_PERM_DENIAL) + deny |= pxace[j].perms; + else + allow |= pxace[j].perms; + j++; + } + /* + * Build the permissions equivalent to grants and denials + */ + if (groupowns) { + if (tag == POSIX_ACL_MASK) + perms = ~deny; + else + perms = allow & ~deny; + } else + switch (tag) { + case POSIX_ACL_USER_OBJ : + perms = (allow | grantgrps | grantwrld) & ~deny; + break; + case POSIX_ACL_USER : + if (id) + perms = (allow | grantgrps | grantwrld) + & ~deny; + else + perms = allow; + break; + case POSIX_ACL_GROUP_OBJ : + perms = (allow | grantwrld) & ~deny; + break; + case POSIX_ACL_GROUP : + if (id) + perms = (allow | grantwrld) & ~deny; + else + perms = allow; + break; + case POSIX_ACL_MASK : + perms = ~deny; + break; + default : + perms = allow & ~deny; + break; + } + /* + * Store into a Posix ACE + */ + if (tag != POSIX_ACL_SPECIAL) { + pxace[k].tag = tag; + pxace[k].id = id; + pxace[k].perms = perms + & (POSIX_PERM_R | POSIX_PERM_W | POSIX_PERM_X); + tagsset |= tag; + k++; + } + switch (tag) { + case POSIX_ACL_USER_OBJ : + mode |= ((perms & 7) << 6); + break; + case POSIX_ACL_GROUP_OBJ : + case POSIX_ACL_MASK : + mode = (mode & 07707) | ((perms & 7) << 3); + break; + case POSIX_ACL_OTHER : + mode |= perms & 7; + break; + case POSIX_ACL_SPECIAL : + mode |= (perms & (S_ISVTX | S_ISUID | S_ISGID)); + break; + default : + break; + } + } + if (!start) { /* not satisfactory */ + posix_desc->mode = mode; + posix_desc->tagsset = tagsset; + } + return (k - target); +} + +#endif /* POSIXACLS */ + +/* + * Interpret an ACL and extract meaningful grants + * (standard case : different owner, group and administrator) + */ + +static int build_std_permissions(const char *securattr, + const SID *usid, const SID *gsid, BOOL isdir) +{ + const SECURITY_DESCRIPTOR_RELATIVE *phead; + const ACL *pacl; + const ACCESS_ALLOWED_ACE *pace; + int offdacl; + int offace; + int acecnt; + int nace; + BOOL noown; + le32 special; + le32 allowown, allowgrp, allowall; + le32 denyown, denygrp, denyall; + + phead = (const SECURITY_DESCRIPTOR_RELATIVE*)securattr; + offdacl = le32_to_cpu(phead->dacl); + pacl = (const ACL*)&securattr[offdacl]; + special = const_cpu_to_le32(0); + allowown = allowgrp = allowall = const_cpu_to_le32(0); + denyown = denygrp = denyall = const_cpu_to_le32(0); + noown = TRUE; + if (offdacl) { + acecnt = le16_to_cpu(pacl->ace_count); + offace = offdacl + sizeof(ACL); + } else { + acecnt = 0; + offace = 0; + } + for (nace = 0; nace < acecnt; nace++) { + pace = (const ACCESS_ALLOWED_ACE*)&securattr[offace]; + if (!(pace->flags & INHERIT_ONLY_ACE)) { + if (ntfs_same_sid(usid, &pace->sid) + || ntfs_same_sid(ownersid, &pace->sid)) { + noown = FALSE; + if (pace->type == ACCESS_ALLOWED_ACE_TYPE) + allowown |= pace->mask; + else if (pace->type == ACCESS_DENIED_ACE_TYPE) + denyown |= pace->mask; + } else + if (ntfs_same_sid(gsid, &pace->sid) + && !(pace->mask & WRITE_OWNER)) { + if (pace->type == ACCESS_ALLOWED_ACE_TYPE) + allowgrp |= pace->mask; + else if (pace->type == ACCESS_DENIED_ACE_TYPE) + denygrp |= pace->mask; + } else + if (is_world_sid((const SID*)&pace->sid)) { + if (pace->type == ACCESS_ALLOWED_ACE_TYPE) + allowall |= pace->mask; + else + if (pace->type == ACCESS_DENIED_ACE_TYPE) + denyall |= pace->mask; + } else + if ((ntfs_same_sid((const SID*)&pace->sid,nullsid)) + && (pace->type == ACCESS_ALLOWED_ACE_TYPE)) + special |= pace->mask; + } + offace += le16_to_cpu(pace->size); + } + /* + * No indication about owner's rights : grant basic rights + * This happens for files created by Windows in directories + * created by Linux and owned by root, because Windows + * merges the admin ACEs + */ + if (noown) + allowown = (FILE_READ_DATA | FILE_WRITE_DATA | FILE_EXECUTE); + /* + * Add to owner rights granted to group or world + * unless denied personaly, and add to group rights + * granted to world unless denied specifically + */ + allowown |= (allowgrp | allowall); + allowgrp |= allowall; + return (merge_permissions(isdir, + allowown & ~(denyown | denyall), + allowgrp & ~(denygrp | denyall), + allowall & ~denyall, + special)); +} + +/* + * Interpret an ACL and extract meaningful grants + * (special case : owner and group are the same, + * and not administrator) + */ + +static int build_owngrp_permissions(const char *securattr, + const SID *usid, BOOL isdir) +{ + const SECURITY_DESCRIPTOR_RELATIVE *phead; + const ACL *pacl; + const ACCESS_ALLOWED_ACE *pace; + int offdacl; + int offace; + int acecnt; + int nace; + le32 special; + BOOL grppresent; + le32 allowown, allowgrp, allowall; + le32 denyown, denygrp, denyall; + + phead = (const SECURITY_DESCRIPTOR_RELATIVE*)securattr; + offdacl = le32_to_cpu(phead->dacl); + pacl = (const ACL*)&securattr[offdacl]; + special = const_cpu_to_le32(0); + allowown = allowgrp = allowall = const_cpu_to_le32(0); + denyown = denygrp = denyall = const_cpu_to_le32(0); + grppresent = FALSE; + if (offdacl) { + acecnt = le16_to_cpu(pacl->ace_count); + offace = offdacl + sizeof(ACL); + } else + acecnt = 0; + for (nace = 0; nace < acecnt; nace++) { + pace = (const ACCESS_ALLOWED_ACE*)&securattr[offace]; + if (!(pace->flags & INHERIT_ONLY_ACE)) { + if ((ntfs_same_sid(usid, &pace->sid) + || ntfs_same_sid(ownersid, &pace->sid)) + && (pace->mask & WRITE_OWNER)) { + if (pace->type == ACCESS_ALLOWED_ACE_TYPE) + allowown |= pace->mask; + } else + if (ntfs_same_sid(usid, &pace->sid) + && (!(pace->mask & WRITE_OWNER))) { + if (pace->type == ACCESS_ALLOWED_ACE_TYPE) { + allowgrp |= pace->mask; + grppresent = TRUE; + } + } else + if (is_world_sid((const SID*)&pace->sid)) { + if (pace->type == ACCESS_ALLOWED_ACE_TYPE) + allowall |= pace->mask; + else + if (pace->type == ACCESS_DENIED_ACE_TYPE) + denyall |= pace->mask; + } else + if ((ntfs_same_sid((const SID*)&pace->sid,nullsid)) + && (pace->type == ACCESS_ALLOWED_ACE_TYPE)) + special |= pace->mask; + } + offace += le16_to_cpu(pace->size); + } + if (!grppresent) + allowgrp = allowall; + return (merge_permissions(isdir, + allowown & ~(denyown | denyall), + allowgrp & ~(denygrp | denyall), + allowall & ~denyall, + special)); +} + +#if POSIXACLS + +/* + * Normalize a Posix ACL either from a sorted raw set of + * access ACEs or default ACEs + * (special case : owner or/and group is administrator) + */ + +static int norm_ownadmin_permissions_posix(struct POSIX_SECURITY *posix_desc, + int start, int count, int target) +{ + int j,k; + s32 id; + u16 tag; + u16 tagsset; + struct POSIX_ACE *pxace; + int acccnt; + mode_t denywrld; + mode_t allow; + mode_t deny; + mode_t perms; + mode_t mode; + + mode = 0; + pxace = posix_desc->acl.ace; + acccnt = posix_desc->acccnt; + tagsset = 0; + denywrld = 0; + /* + * Get denials to world which are meant to prevent + * execution flags to be inherited by plain files + */ + for (j=start; j<(start + count); j++) { + if (pxace[j].perms & POSIX_PERM_DENIAL) { + /* deny world exec not for default */ + if ((pxace[j].tag == POSIX_ACL_OTHER) + && !start) + denywrld = pxace[j].perms; + } + } + /* + * Collect groups of ACEs related to the same id + * and determine what is granted (denials are ignored) + * It is important the ACEs have been sorted + */ + j = start; + k = target; + deny = 0; + while (j < (start + count)) { + allow = 0; + tag = pxace[j].tag; + id = pxace[j].id; + if (tag == POSIX_ACL_MASK) { + deny = pxace[j].perms; + j++; + while ((j < (start + count)) + && (pxace[j].tag == POSIX_ACL_MASK)) + j++; + } else { + if (!(pxace[j].perms & POSIX_PERM_DENIAL)) + allow = pxace[j].perms; + j++; + while ((j < (start + count)) + && (pxace[j].tag == tag) + && (pxace[j].id == id)) { + if (!(pxace[j].perms & POSIX_PERM_DENIAL)) + allow |= pxace[j].perms; + j++; + } + } + + /* + * Store the grants into a Posix ACE + */ + if (tag == POSIX_ACL_MASK) + perms = ~deny; + else + perms = allow & ~denywrld; + if (tag != POSIX_ACL_SPECIAL) { + pxace[k].tag = tag; + pxace[k].id = id; + pxace[k].perms = perms + & (POSIX_PERM_R | POSIX_PERM_W | POSIX_PERM_X); + tagsset |= tag; + k++; + } + switch (tag) { + case POSIX_ACL_USER_OBJ : + mode |= ((perms & 7) << 6); + break; + case POSIX_ACL_GROUP_OBJ : + case POSIX_ACL_MASK : + mode = (mode & 07707) | ((perms & 7) << 3); + break; + case POSIX_ACL_OTHER : + mode |= perms & 7; + break; + case POSIX_ACL_SPECIAL : + mode |= perms & (S_ISVTX | S_ISUID | S_ISGID); + break; + default : + break; + } + } + if (!start) { /* not satisfactory */ + posix_desc->mode = mode; + posix_desc->tagsset = tagsset; + } + return (k - target); +} + +#endif /* POSIXACLS */ + +/* + * Interpret an ACL and extract meaningful grants + * (special case : owner or/and group is administrator) + */ + + +static int build_ownadmin_permissions(const char *securattr, + const SID *usid, const SID *gsid, BOOL isdir) +{ + const SECURITY_DESCRIPTOR_RELATIVE *phead; + const ACL *pacl; + const ACCESS_ALLOWED_ACE *pace; + int offdacl; + int offace; + int acecnt; + int nace; + BOOL firstapply; + int isforeign; + le32 special; + le32 allowown, allowgrp, allowall; + le32 denyown, denygrp, denyall; + + phead = (const SECURITY_DESCRIPTOR_RELATIVE*)securattr; + offdacl = le32_to_cpu(phead->dacl); + pacl = (const ACL*)&securattr[offdacl]; + special = const_cpu_to_le32(0); + allowown = allowgrp = allowall = const_cpu_to_le32(0); + denyown = denygrp = denyall = const_cpu_to_le32(0); + if (offdacl) { + acecnt = le16_to_cpu(pacl->ace_count); + offace = offdacl + sizeof(ACL); + } else { + acecnt = 0; + offace = 0; + } + firstapply = TRUE; + isforeign = 3; + for (nace = 0; nace < acecnt; nace++) { + pace = (const ACCESS_ALLOWED_ACE*)&securattr[offace]; + if (!(pace->flags & INHERIT_ONLY_ACE) + && !(~pace->mask & (ROOT_OWNER_UNMARK | ROOT_GROUP_UNMARK))) { + if ((ntfs_same_sid(usid, &pace->sid) + || ntfs_same_sid(ownersid, &pace->sid)) + && (((pace->mask & WRITE_OWNER) && firstapply))) { + if (pace->type == ACCESS_ALLOWED_ACE_TYPE) { + allowown |= pace->mask; + isforeign &= ~1; + } else + if (pace->type == ACCESS_DENIED_ACE_TYPE) + denyown |= pace->mask; + } else + if (ntfs_same_sid(gsid, &pace->sid) + && (!(pace->mask & WRITE_OWNER))) { + if (pace->type == ACCESS_ALLOWED_ACE_TYPE) { + allowgrp |= pace->mask; + isforeign &= ~2; + } else + if (pace->type == ACCESS_DENIED_ACE_TYPE) + denygrp |= pace->mask; + } else if (is_world_sid((const SID*)&pace->sid)) { + if (pace->type == ACCESS_ALLOWED_ACE_TYPE) + allowall |= pace->mask; + else + if (pace->type == ACCESS_DENIED_ACE_TYPE) + denyall |= pace->mask; + } + firstapply = FALSE; + } else + if (!(pace->flags & INHERIT_ONLY_ACE)) + if ((ntfs_same_sid((const SID*)&pace->sid,nullsid)) + && (pace->type == ACCESS_ALLOWED_ACE_TYPE)) + special |= pace->mask; + offace += le16_to_cpu(pace->size); + } + if (isforeign) { + allowown |= (allowgrp | allowall); + allowgrp |= allowall; + } + return (merge_permissions(isdir, + allowown & ~(denyown | denyall), + allowgrp & ~(denygrp | denyall), + allowall & ~denyall, + special)); +} + +#if OWNERFROMACL + +/* + * Define the owner of a file as the first user allowed + * to change the owner, instead of the user defined as owner. + * + * This produces better approximations for files written by a + * Windows user in an inheritable directory owned by another user, + * as the access rights are inheritable but the ownership is not. + * + * An important case is the directories "Documents and Settings/user" + * which the users must have access to, though Windows considers them + * as owned by administrator. + */ + +const SID *ntfs_acl_owner(const char *securattr) +{ + const SECURITY_DESCRIPTOR_RELATIVE *phead; + const SID *usid; + const ACL *pacl; + const ACCESS_ALLOWED_ACE *pace; + int offdacl; + int offace; + int acecnt; + int nace; + BOOL found; + + found = FALSE; + phead = (const SECURITY_DESCRIPTOR_RELATIVE*)securattr; + offdacl = le32_to_cpu(phead->dacl); + if (offdacl) { + pacl = (const ACL*)&securattr[offdacl]; + acecnt = le16_to_cpu(pacl->ace_count); + offace = offdacl + sizeof(ACL); + nace = 0; + do { + pace = (const ACCESS_ALLOWED_ACE*)&securattr[offace]; + if ((pace->mask & WRITE_OWNER) + && (pace->type == ACCESS_ALLOWED_ACE_TYPE) + && ntfs_is_user_sid(&pace->sid)) + found = TRUE; + offace += le16_to_cpu(pace->size); + } while (!found && (++nace < acecnt)); + } + if (found) + usid = &pace->sid; + else + usid = (const SID*)&securattr[le32_to_cpu(phead->owner)]; + return (usid); +} + +#else + +/* + * Special case for files owned by administrator with full + * access granted to a mapped user : consider this user as the tenant + * of the file. + * + * This situation cannot be represented with Linux concepts and can + * only be found for files or directories created by Windows. + * Typical situation : directory "Documents and Settings/user" which + * is on the path to user's files and must be given access to user + * only. + * + * Check file is owned by administrator and no user has rights before + * calling. + * Returns the uid of tenant or zero if none + */ + + +static uid_t find_tenant(struct MAPPING *const mapping[], + const char *securattr) +{ + const SECURITY_DESCRIPTOR_RELATIVE *phead; + const ACL *pacl; + const ACCESS_ALLOWED_ACE *pace; + int offdacl; + int offace; + int acecnt; + int nace; + uid_t tid; + uid_t xid; + + phead = (const SECURITY_DESCRIPTOR_RELATIVE*)securattr; + offdacl = le32_to_cpu(phead->dacl); + pacl = (const ACL*)&securattr[offdacl]; + tid = 0; + if (offdacl) { + acecnt = le16_to_cpu(pacl->ace_count); + offace = offdacl + sizeof(ACL); + } else + acecnt = 0; + for (nace = 0; nace < acecnt; nace++) { + pace = (const ACCESS_ALLOWED_ACE*)&securattr[offace]; + if ((pace->type == ACCESS_ALLOWED_ACE_TYPE) + && (pace->mask & DIR_WRITE)) { + xid = NTFS_FIND_USER(mapping[MAPUSERS], &pace->sid); + if (xid) tid = xid; + } + offace += le16_to_cpu(pace->size); + } + return (tid); +} + +#endif /* OWNERFROMACL */ + +#if POSIXACLS + +/* + * Build Posix permissions from an ACL + * returns a pointer to the requested permissions + * or a null pointer (with errno set) if there is a problem + * + * If the NTFS ACL was created according to our rules, the retrieved + * Posix ACL should be the exact ACL which was set. However if + * the NTFS ACL was built by a different tool, the result could + * be a a poor approximation of what was expected + */ + +struct POSIX_SECURITY *ntfs_build_permissions_posix( + struct MAPPING *const mapping[], + const char *securattr, + const SID *usid, const SID *gsid, BOOL isdir) +{ + const SECURITY_DESCRIPTOR_RELATIVE *phead; + struct POSIX_SECURITY *pxdesc; + const ACL *pacl; + const ACCESS_ALLOWED_ACE *pace; + struct POSIX_ACE *pxace; + struct { + uid_t prevuid; + gid_t prevgid; + int groupmasks; + s16 tagsset; + BOOL gotowner; + BOOL gotownermask; + BOOL gotgroup; + mode_t permswrld; + } ctx[2], *pctx; + int offdacl; + int offace; + int alloccnt; + int acecnt; + uid_t uid; + gid_t gid; + int i,j; + int k,l; + BOOL ignore; + BOOL adminowns; + BOOL groupowns; + BOOL firstinh; + BOOL genericinh; + + phead = (const SECURITY_DESCRIPTOR_RELATIVE*)securattr; + offdacl = le32_to_cpu(phead->dacl); + if (offdacl) { + pacl = (const ACL*)&securattr[offdacl]; + acecnt = le16_to_cpu(pacl->ace_count); + offace = offdacl + sizeof(ACL); + } else { + acecnt = 0; + offace = 0; + } + adminowns = FALSE; + groupowns = ntfs_same_sid(gsid,usid); + firstinh = FALSE; + genericinh = FALSE; + /* + * Build a raw posix security descriptor + * by just translating permissions and ids + * Add 2 to the count of ACE to be able to insert + * a group ACE later in access and default ACLs + * and add 2 more to be able to insert ACEs for owner + * and 2 more for other + */ + alloccnt = acecnt + 6; + pxdesc = (struct POSIX_SECURITY*)malloc( + sizeof(struct POSIX_SECURITY) + + alloccnt*sizeof(struct POSIX_ACE)); + k = 0; + l = alloccnt; + for (i=0; i<2; i++) { + pctx = &ctx[i]; + pctx->permswrld = 0; + pctx->prevuid = -1; + pctx->prevgid = -1; + pctx->groupmasks = 0; + pctx->tagsset = 0; + pctx->gotowner = FALSE; + pctx->gotgroup = FALSE; + pctx->gotownermask = FALSE; + } + for (j=0; jflags & INHERIT_ONLY_ACE) { + pxace = &pxdesc->acl.ace[l - 1]; + pctx = &ctx[1]; + } else { + pxace = &pxdesc->acl.ace[k]; + pctx = &ctx[0]; + } + ignore = FALSE; + /* + * grants for root as a designated user or group + */ + if ((~pace->mask & (ROOT_OWNER_UNMARK | ROOT_GROUP_UNMARK)) + && (pace->type == ACCESS_ALLOWED_ACE_TYPE) + && ntfs_same_sid(&pace->sid, adminsid)) { + pxace->tag = (pace->mask & ROOT_OWNER_UNMARK ? POSIX_ACL_GROUP : POSIX_ACL_USER); + pxace->id = 0; + if ((pace->mask & (GENERIC_ALL | WRITE_OWNER)) + && (pace->flags & INHERIT_ONLY_ACE)) + ignore = genericinh = TRUE; + } else + if (ntfs_same_sid(usid, &pace->sid)) { + pxace->id = -1; + /* + * Owner has no write-owner right : + * a group was defined same as owner + * or admin was owner or group : + * denials are meant to owner + * and grants are meant to group + */ + if (!(pace->mask & (WRITE_OWNER | GENERIC_ALL)) + && (pace->type == ACCESS_ALLOWED_ACE_TYPE)) { + if (ntfs_same_sid(gsid,usid)) { + pxace->tag = POSIX_ACL_GROUP_OBJ; + pxace->id = -1; + } else { + if (ntfs_same_sid(&pace->sid,usid)) + groupowns = TRUE; + gid = NTFS_FIND_GROUP(mapping[MAPGROUPS],&pace->sid); + if (gid) { + pxace->tag = POSIX_ACL_GROUP; + pxace->id = gid; + pctx->prevgid = gid; + } else { + uid = NTFS_FIND_USER(mapping[MAPUSERS],&pace->sid); + if (uid) { + pxace->tag = POSIX_ACL_USER; + pxace->id = uid; + } else + ignore = TRUE; + } + } + } else { + /* + * when group owns, late denials for owner + * mean group mask + */ + if ((pace->type == ACCESS_DENIED_ACE_TYPE) + && (pace->mask & WRITE_OWNER)) { + pxace->tag = POSIX_ACL_MASK; + pctx->gotownermask = TRUE; + if (pctx->gotowner) + pctx->groupmasks++; + } else { + if (pace->type == ACCESS_ALLOWED_ACE_TYPE) + pctx->gotowner = TRUE; + if (pctx->gotownermask && !pctx->gotowner) { + uid = NTFS_FIND_USER(mapping[MAPUSERS],&pace->sid); + pxace->id = uid; + pxace->tag = POSIX_ACL_USER; + } else + pxace->tag = POSIX_ACL_USER_OBJ; + /* system ignored, and admin */ + /* ignored at first position */ + if (pace->flags & INHERIT_ONLY_ACE) { + if ((firstinh && ntfs_same_sid(&pace->sid,adminsid)) + || ntfs_same_sid(&pace->sid,systemsid)) + ignore = TRUE; + if (!firstinh) { + firstinh = TRUE; + } + } else { + if ((adminowns && ntfs_same_sid(&pace->sid,adminsid)) + || ntfs_same_sid(&pace->sid,systemsid)) + ignore = TRUE; + if (ntfs_same_sid(usid,adminsid)) + adminowns = TRUE; + } + } + } + } else if (ntfs_same_sid(gsid, &pace->sid)) { + if ((pace->type == ACCESS_DENIED_ACE_TYPE) + && (pace->mask & WRITE_OWNER)) { + pxace->tag = POSIX_ACL_MASK; + pxace->id = -1; + if (pctx->gotowner) + pctx->groupmasks++; + } else { + if (pctx->gotgroup || (pctx->groupmasks > 1)) { + gid = NTFS_FIND_GROUP(mapping[MAPGROUPS],&pace->sid); + if (gid) { + pxace->id = gid; + pxace->tag = POSIX_ACL_GROUP; + pctx->prevgid = gid; + } else + ignore = TRUE; + } else { + pxace->id = -1; + pxace->tag = POSIX_ACL_GROUP_OBJ; + if (pace->type == ACCESS_ALLOWED_ACE_TYPE) + pctx->gotgroup = TRUE; + } + + if (ntfs_same_sid(gsid,adminsid) + || ntfs_same_sid(gsid,systemsid)) { + if (pace->mask & (WRITE_OWNER | GENERIC_ALL)) + ignore = TRUE; + if (ntfs_same_sid(gsid,adminsid)) + adminowns = TRUE; + else + genericinh = ignore; + } + } + } else if (is_world_sid((const SID*)&pace->sid)) { + pxace->id = -1; + pxace->tag = POSIX_ACL_OTHER; + if ((pace->type == ACCESS_DENIED_ACE_TYPE) + && (pace->flags & INHERIT_ONLY_ACE)) + ignore = TRUE; + } else if (ntfs_same_sid((const SID*)&pace->sid,nullsid)) { + pxace->id = -1; + pxace->tag = POSIX_ACL_SPECIAL; + } else { + uid = NTFS_FIND_USER(mapping[MAPUSERS],&pace->sid); + if (uid) { + if ((pace->type == ACCESS_DENIED_ACE_TYPE) + && (pace->mask & WRITE_OWNER) + && (pctx->prevuid != uid)) { + pxace->id = -1; + pxace->tag = POSIX_ACL_MASK; + } else { + pxace->id = uid; + pxace->tag = POSIX_ACL_USER; + } + pctx->prevuid = uid; + } else { + gid = NTFS_FIND_GROUP(mapping[MAPGROUPS],&pace->sid); + if (gid) { + if ((pace->type == ACCESS_DENIED_ACE_TYPE) + && (pace->mask & WRITE_OWNER) + && (pctx->prevgid != gid)) { + pxace->tag = POSIX_ACL_MASK; + pctx->groupmasks++; + } else { + pxace->tag = POSIX_ACL_GROUP; + } + pxace->id = gid; + pctx->prevgid = gid; + } else { + /* + * do not grant rights to unknown + * people and do not define root as a + * designated user or group + */ + ignore = TRUE; + } + } + } + if (!ignore) { + pxace->perms = 0; + /* specific decoding for vtx/uid/gid */ + if (pxace->tag == POSIX_ACL_SPECIAL) { + if (pace->mask & FILE_APPEND_DATA) + pxace->perms |= S_ISUID; + if (pace->mask & FILE_WRITE_DATA) + pxace->perms |= S_ISGID; + if (pace->mask & FILE_READ_DATA) + pxace->perms |= S_ISVTX; + } else + if (isdir) { + if (pace->mask & DIR_GEXEC) + pxace->perms |= POSIX_PERM_X; + if (pace->mask & DIR_GWRITE) + pxace->perms |= POSIX_PERM_W; + if (pace->mask & DIR_GREAD) + pxace->perms |= POSIX_PERM_R; + if ((pace->mask & GENERIC_ALL) + && (pace->flags & INHERIT_ONLY_ACE)) + pxace->perms |= POSIX_PERM_X + | POSIX_PERM_W + | POSIX_PERM_R; + } else { + if (pace->mask & FILE_GEXEC) + pxace->perms |= POSIX_PERM_X; + if (pace->mask & FILE_GWRITE) + pxace->perms |= POSIX_PERM_W; + if (pace->mask & FILE_GREAD) + pxace->perms |= POSIX_PERM_R; + } + + if (pace->type != ACCESS_ALLOWED_ACE_TYPE) + pxace->perms |= POSIX_PERM_DENIAL; + else + if (pxace->tag == POSIX_ACL_OTHER) + pctx->permswrld = pxace->perms; + pctx->tagsset |= pxace->tag; + if (pace->flags & INHERIT_ONLY_ACE) { + l--; + } else { + k++; + } + } + offace += le16_to_cpu(pace->size); + } + /* + * Create world perms if none (both lists) + */ + for (i=0; i<2; i++) + if ((genericinh || !i) + && !(ctx[i].tagsset & POSIX_ACL_OTHER)) { + if (i) + pxace = &pxdesc->acl.ace[--l]; + else + pxace = &pxdesc->acl.ace[k++]; + pxace->tag = POSIX_ACL_OTHER; + pxace->id = -1; + pxace->perms = 0; + ctx[i].tagsset |= POSIX_ACL_OTHER; + ctx[i].permswrld = 0; + } + /* + * Set basic owner perms if none (both lists) + * This happens for files created by Windows in directories + * created by Linux and owned by root, because Windows + * merges the admin ACEs + */ + for (i=0; i<2; i++) + if (!(ctx[i].tagsset & POSIX_ACL_USER_OBJ) + && (ctx[i].tagsset & POSIX_ACL_OTHER)) { + if (i) + pxace = &pxdesc->acl.ace[--l]; + else + pxace = &pxdesc->acl.ace[k++]; + pxace->tag = POSIX_ACL_USER_OBJ; + pxace->id = -1; + pxace->perms = POSIX_PERM_R | POSIX_PERM_W | POSIX_PERM_X; + ctx[i].tagsset |= POSIX_ACL_USER_OBJ; + } + /* + * Duplicate world perms as group_obj perms if none + */ + for (i=0; i<2; i++) + if ((ctx[i].tagsset & POSIX_ACL_OTHER) + && !(ctx[i].tagsset & POSIX_ACL_GROUP_OBJ)) { + if (i) + pxace = &pxdesc->acl.ace[--l]; + else + pxace = &pxdesc->acl.ace[k++]; + pxace->tag = POSIX_ACL_GROUP_OBJ; + pxace->id = -1; + pxace->perms = ctx[i].permswrld; + ctx[i].tagsset |= POSIX_ACL_GROUP_OBJ; + } + /* + * Also duplicate world perms as group perms if they + * were converted to mask and not followed by a group entry + */ + if (ctx[0].groupmasks) { + for (j=k-2; j>=0; j--) { + if ((pxdesc->acl.ace[j].tag == POSIX_ACL_MASK) + && (pxdesc->acl.ace[j].id != -1) + && ((pxdesc->acl.ace[j+1].tag != POSIX_ACL_GROUP) + || (pxdesc->acl.ace[j+1].id + != pxdesc->acl.ace[j].id))) { + pxace = &pxdesc->acl.ace[k]; + pxace->tag = POSIX_ACL_GROUP; + pxace->id = pxdesc->acl.ace[j].id; + pxace->perms = ctx[0].permswrld; + ctx[0].tagsset |= POSIX_ACL_GROUP; + k++; + } + if (pxdesc->acl.ace[j].tag == POSIX_ACL_MASK) + pxdesc->acl.ace[j].id = -1; + } + } + if (ctx[1].groupmasks) { + for (j=l; j<(alloccnt-1); j++) { + if ((pxdesc->acl.ace[j].tag == POSIX_ACL_MASK) + && (pxdesc->acl.ace[j].id != -1) + && ((pxdesc->acl.ace[j+1].tag != POSIX_ACL_GROUP) + || (pxdesc->acl.ace[j+1].id + != pxdesc->acl.ace[j].id))) { + pxace = &pxdesc->acl.ace[l - 1]; + pxace->tag = POSIX_ACL_GROUP; + pxace->id = pxdesc->acl.ace[j].id; + pxace->perms = ctx[1].permswrld; + ctx[1].tagsset |= POSIX_ACL_GROUP; + l--; + } + if (pxdesc->acl.ace[j].tag == POSIX_ACL_MASK) + pxdesc->acl.ace[j].id = -1; + } + } + + /* + * Insert default mask if none present and + * there are designated users or groups + * (the space for it has not beed used) + */ + for (i=0; i<2; i++) + if ((ctx[i].tagsset & (POSIX_ACL_USER | POSIX_ACL_GROUP)) + && !(ctx[i].tagsset & POSIX_ACL_MASK)) { + if (i) + pxace = &pxdesc->acl.ace[--l]; + else + pxace = &pxdesc->acl.ace[k++]; + pxace->tag = POSIX_ACL_MASK; + pxace->id = -1; + pxace->perms = POSIX_PERM_DENIAL; + ctx[i].tagsset |= POSIX_ACL_MASK; + } + + if (k > l) { + ntfs_log_error("Posix descriptor is longer than expected\n"); + errno = EIO; + free(pxdesc); + pxdesc = (struct POSIX_SECURITY*)NULL; + } else { + pxdesc->acccnt = k; + pxdesc->defcnt = alloccnt - l; + pxdesc->firstdef = l; + pxdesc->tagsset = ctx[0].tagsset; + pxdesc->acl.version = POSIX_VERSION; + pxdesc->acl.flags = 0; + pxdesc->acl.filler = 0; + ntfs_sort_posix(pxdesc); + if (adminowns) { + k = norm_ownadmin_permissions_posix(pxdesc, + 0, pxdesc->acccnt, 0); + pxdesc->acccnt = k; + l = norm_ownadmin_permissions_posix(pxdesc, + pxdesc->firstdef, pxdesc->defcnt, k); + pxdesc->firstdef = k; + pxdesc->defcnt = l; + } else { + k = norm_std_permissions_posix(pxdesc,groupowns, + 0, pxdesc->acccnt, 0); + pxdesc->acccnt = k; + l = norm_std_permissions_posix(pxdesc,groupowns, + pxdesc->firstdef, pxdesc->defcnt, k); + pxdesc->firstdef = k; + pxdesc->defcnt = l; + } + } + if (pxdesc && !ntfs_valid_posix(pxdesc)) { + ntfs_log_error("Invalid Posix descriptor built\n"); + errno = EIO; + free(pxdesc); + pxdesc = (struct POSIX_SECURITY*)NULL; + } + return (pxdesc); +} + +#endif /* POSIXACLS */ + +/* + * Build unix-style (mode_t) permissions from an ACL + * returns the requested permissions + * or a negative result (with errno set) if there is a problem + */ + +int ntfs_build_permissions(const char *securattr, + const SID *usid, const SID *gsid, BOOL isdir) +{ + const SECURITY_DESCRIPTOR_RELATIVE *phead; + int perm; + BOOL adminowns; + BOOL groupowns; + + phead = (const SECURITY_DESCRIPTOR_RELATIVE*)securattr; + adminowns = ntfs_same_sid(usid,adminsid) + || ntfs_same_sid(gsid,adminsid); + groupowns = !adminowns && ntfs_same_sid(gsid,usid); + if (adminowns) + perm = build_ownadmin_permissions(securattr, usid, gsid, isdir); + else + if (groupowns) + perm = build_owngrp_permissions(securattr, usid, isdir); + else + perm = build_std_permissions(securattr, usid, gsid, isdir); + return (perm); +} + +/* + * The following must be in some library... + */ + +static unsigned long atoul(const char *p) +{ /* must be somewhere ! */ + unsigned long v; + + v = 0; + while ((*p >= '0') && (*p <= '9')) + v = v * 10 + (*p++) - '0'; + return (v); +} + +/* + * Build an internal representation of a SID + * Returns a copy in allocated memory if it succeeds + * The SID is checked to be a valid user one. + */ + +static SID *encodesid(const char *sidstr) +{ + SID *sid; + int cnt; + BIGSID bigsid; + SID *bsid; + u32 auth; + const char *p; + + sid = (SID*) NULL; + if (!strncmp(sidstr, "S-1-", 4)) { + bsid = (SID*)&bigsid; + bsid->revision = SID_REVISION; + p = &sidstr[4]; + auth = atoul(p); + bsid->identifier_authority.high_part = const_cpu_to_be16(0); + bsid->identifier_authority.low_part = cpu_to_be32(auth); + cnt = 0; + p = strchr(p, '-'); + while (p && (cnt < 8)) { + p++; + auth = atoul(p); + bsid->sub_authority[cnt] = cpu_to_le32(auth); + p = strchr(p, '-'); + cnt++; + } + bsid->sub_authority_count = cnt; + if ((cnt > 0) && ntfs_valid_sid(bsid) && ntfs_is_user_sid(bsid)) { + sid = (SID*) ntfs_malloc(4 * cnt + 8); + if (sid) + memcpy(sid, bsid, 4 * cnt + 8); + } + } + return (sid); +} + +/* + * Early logging before the logs are redirected + * + * (not quite satisfactory : this appears before the ntfs-g banner, + * and with a different pid) + */ + +static void log_early_error(const char *format, ...) + __attribute__((format(printf, 1, 2))); + +static void log_early_error(const char *format, ...) +{ + va_list args; + + va_start(args, format); +#ifdef HAVE_SYSLOG_H + openlog("ntfs-3g", LOG_PID, LOG_USER); + ntfs_log_handler_syslog(NULL, NULL, 0, + NTFS_LOG_LEVEL_ERROR, NULL, + format, args); +#else + vfprintf(stderr,format,args); +#endif + va_end(args); +} + + +/* + * Get a single mapping item from buffer + * + * Always reads a full line, truncating long lines + * Refills buffer when exhausted + * Returns pointer to item, or NULL when there is no more + */ + +static struct MAPLIST *getmappingitem(FILEREADER reader, void *fileid, + off_t *poffs, char *buf, int *psrc, s64 *psize) +{ + int src; + int dst; + char *p; + char *q; + char *pu; + char *pg; + int gotend; + struct MAPLIST *item; + + src = *psrc; + dst = 0; + /* allocate and get a full line */ + item = (struct MAPLIST*)ntfs_malloc(sizeof(struct MAPLIST)); + if (item) { + do { + gotend = 0; + while ((src < *psize) + && (buf[src] != '\n')) { + if (dst < LINESZ) + item->maptext[dst++] = buf[src]; + src++; + } + if (src >= *psize) { + *poffs += *psize; + *psize = reader(fileid, buf, (size_t)BUFSZ, *poffs); + src = 0; + } else { + gotend = 1; + src++; + item->maptext[dst] = '\0'; + dst = 0; + } + } while (*psize && ((item->maptext[0] == '#') || !gotend)); + if (gotend) { + pu = pg = (char*)NULL; + /* decompose into uid, gid and sid */ + p = item->maptext; + item->uidstr = item->maptext; + item->gidstr = strchr(item->uidstr, ':'); + if (item->gidstr) { + pu = item->gidstr++; + item->sidstr = strchr(item->gidstr, ':'); + if (item->sidstr) { + pg = item->sidstr++; + q = strchr(item->sidstr, ':'); + if (q) *q = 0; + } + } + if (pu && pg) + *pu = *pg = '\0'; + else { + log_early_error("Bad mapping item \"%s\"\n", + item->maptext); + free(item); + item = (struct MAPLIST*)NULL; + } + } else { + free(item); /* free unused item */ + item = (struct MAPLIST*)NULL; + } + } + *psrc = src; + return (item); +} + +/* + * Read user mapping file and split into their attribute. + * Parameters are kept as text in a chained list until logins + * are converted to uid. + * Returns the head of list, if any + * + * If an absolute path is provided, the mapping file is assumed + * to be located in another mounted file system, and plain read() + * are used to get its contents. + * If a relative path is provided, the mapping file is assumed + * to be located on the current file system, and internal IO + * have to be used since we are still mounting and we have not + * entered the fuse loop yet. + */ + +struct MAPLIST *ntfs_read_mapping(FILEREADER reader, void *fileid) +{ + char buf[BUFSZ]; + struct MAPLIST *item; + struct MAPLIST *firstitem; + struct MAPLIST *lastitem; + int src; + off_t offs; + s64 size; + + firstitem = (struct MAPLIST*)NULL; + lastitem = (struct MAPLIST*)NULL; + offs = 0; + size = reader(fileid, buf, (size_t)BUFSZ, (off_t)0); + if (size > 0) { + src = 0; + do { + item = getmappingitem(reader, fileid, &offs, + buf, &src, &size); + if (item) { + item->next = (struct MAPLIST*)NULL; + if (lastitem) + lastitem->next = item; + else + firstitem = item; + lastitem = item; + } + } while (item); + } + return (firstitem); +} + +/* + * Free memory used to store the user mapping + * The only purpose is to facilitate the detection of memory leaks + */ + +void ntfs_free_mapping(struct MAPPING *mapping[]) +{ + struct MAPPING *user; + struct MAPPING *group; + + /* free user mappings */ + while (mapping[MAPUSERS]) { + user = mapping[MAPUSERS]; + /* do not free SIDs used for group mappings */ + group = mapping[MAPGROUPS]; + while (group && (group->sid != user->sid)) + group = group->next; + if (!group) + free(user->sid); + /* free group list if any */ + if (user->grcnt) + free(user->groups); + /* unchain item and free */ + mapping[MAPUSERS] = user->next; + free(user); + } + /* free group mappings */ + while (mapping[MAPGROUPS]) { + group = mapping[MAPGROUPS]; + free(group->sid); + /* unchain item and free */ + mapping[MAPGROUPS] = group->next; + free(group); + } +} + + +/* + * Build the user mapping list + * user identification may be given in symbolic or numeric format + * + * ! Note ! : does getpwnam() read /etc/passwd or some other file ? + * if so there is a possible recursion into fuse if this + * file is on NTFS, and fuse is not recursion safe. + */ + +struct MAPPING *ntfs_do_user_mapping(struct MAPLIST *firstitem) +{ + struct MAPLIST *item; + struct MAPPING *firstmapping; + struct MAPPING *lastmapping; + struct MAPPING *mapping; + struct passwd *pwd; + SID *sid; + int uid; + + firstmapping = (struct MAPPING*)NULL; + lastmapping = (struct MAPPING*)NULL; + for (item = firstitem; item; item = item->next) { + if ((item->uidstr[0] >= '0') && (item->uidstr[0] <= '9')) + uid = atoi(item->uidstr); + else { + uid = 0; + if (item->uidstr[0]) { + pwd = getpwnam(item->uidstr); + if (pwd) + uid = pwd->pw_uid; + else + log_early_error("Invalid user \"%s\"\n", + item->uidstr); + } + } + /* + * Records with no uid and no gid are inserted + * to define the implicit mapping pattern + */ + if (uid + || (!item->uidstr[0] && !item->gidstr[0])) { + sid = encodesid(item->sidstr); + if (sid && !item->uidstr[0] && !item->gidstr[0] + && !ntfs_valid_pattern(sid)) { + ntfs_log_error("Bad implicit SID pattern %s\n", + item->sidstr); + sid = (SID*)NULL; + } + if (sid) { + mapping = + (struct MAPPING*) + ntfs_malloc(sizeof(struct MAPPING)); + if (mapping) { + mapping->sid = sid; + mapping->xid = uid; + mapping->grcnt = 0; + mapping->next = (struct MAPPING*)NULL; + if (lastmapping) + lastmapping->next = mapping; + else + firstmapping = mapping; + lastmapping = mapping; + } + } + } + } + return (firstmapping); +} + +/* + * Build the group mapping list + * group identification may be given in symbolic or numeric format + * + * gid not associated to a uid are processed first in order + * to favour real groups + * + * ! Note ! : does getgrnam() read /etc/group or some other file ? + * if so there is a possible recursion into fuse if this + * file is on NTFS, and fuse is not recursion safe. + */ + +struct MAPPING *ntfs_do_group_mapping(struct MAPLIST *firstitem) +{ + struct MAPLIST *item; + struct MAPPING *firstmapping; + struct MAPPING *lastmapping; + struct MAPPING *mapping; + struct group *grp; + BOOL secondstep; + BOOL ok; + int step; + SID *sid; + int gid; + + firstmapping = (struct MAPPING*)NULL; + lastmapping = (struct MAPPING*)NULL; + for (step=1; step<=2; step++) { + for (item = firstitem; item; item = item->next) { + secondstep = (item->uidstr[0] != '\0') + || !item->gidstr[0]; + ok = (step == 1 ? !secondstep : secondstep); + if ((item->gidstr[0] >= '0') + && (item->gidstr[0] <= '9')) + gid = atoi(item->gidstr); + else { + gid = 0; + if (item->gidstr[0]) { + grp = getgrnam(item->gidstr); + if (grp) + gid = grp->gr_gid; + else + log_early_error("Invalid group \"%s\"\n", + item->gidstr); + } + } + /* + * Records with no uid and no gid are inserted in the + * second step to define the implicit mapping pattern + */ + if (ok + && (gid + || (!item->uidstr[0] && !item->gidstr[0]))) { + sid = encodesid(item->sidstr); + if (sid && !item->uidstr[0] && !item->gidstr[0] + && !ntfs_valid_pattern(sid)) { + /* error already logged */ + sid = (SID*)NULL; + } + if (sid) { + mapping = (struct MAPPING*) + ntfs_malloc(sizeof(struct MAPPING)); + if (mapping) { + mapping->sid = sid; + mapping->xid = gid; + mapping->grcnt = 0; + mapping->next = (struct MAPPING*)NULL; + if (lastmapping) + lastmapping->next = mapping; + else + firstmapping = mapping; + lastmapping = mapping; + } + } + } + } + } + return (firstmapping); +} diff --git a/libntfs-3g/attrib.c b/libntfs-3g/attrib.c new file mode 100755 index 0000000..12ea369 --- a/dev/null +++ b/libntfs-3g/attrib.c @@ -0,0 +1,5913 @@ +/** + * attrib.c - Attribute handling code. Originated from the Linux-NTFS project. + * + * Copyright (c) 2000-2010 Anton Altaparmakov + * Copyright (c) 2002-2005 Richard Russon + * Copyright (c) 2002-2008 Szabolcs Szakacsits + * Copyright (c) 2004-2007 Yura Pakhuchiy + * Copyright (c) 2007-2010 Jean-Pierre Andre + * Copyright (c) 2010 Erik Larsson + * + * This program/include file 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/include file 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 (in the main directory of the NTFS-3G + * distribution in the file COPYING); if not, write to the Free Software + * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_STDIO_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_ERRNO_H +#include +#endif +#ifdef HAVE_LIMITS_H +#include +#endif + +#include "param.h" +#include "compat.h" +#include "attrib.h" +#include "attrlist.h" +#include "device.h" +#include "mft.h" +#include "debug.h" +#include "mst.h" +#include "volume.h" +#include "types.h" +#include "layout.h" +#include "inode.h" +#include "runlist.h" +#include "lcnalloc.h" +#include "dir.h" +#include "compress.h" +#include "bitmap.h" +#include "logging.h" +#include "misc.h" +#include "efs.h" + +#define STANDARD_COMPRESSION_UNIT 4 +#define MAX_COMPRESSION_CLUSTER_SIZE 4096 + +ntfschar AT_UNNAMED[] = { const_cpu_to_le16('\0') }; +ntfschar STREAM_SDS[] = { const_cpu_to_le16('$'), + const_cpu_to_le16('S'), + const_cpu_to_le16('D'), + const_cpu_to_le16('S'), + const_cpu_to_le16('\0') }; + +ntfschar TXF_DATA[] = { const_cpu_to_le16('$'), + const_cpu_to_le16('T'), + const_cpu_to_le16('X'), + const_cpu_to_le16('F'), + const_cpu_to_le16('_'), + const_cpu_to_le16('D'), + const_cpu_to_le16('A'), + const_cpu_to_le16('T'), + const_cpu_to_le16('A'), + const_cpu_to_le16('\0') }; + +static int NAttrFlag(ntfs_attr *na, FILE_ATTR_FLAGS flag) +{ + if (na->type == AT_DATA && na->name == AT_UNNAMED) + return (na->ni->flags & flag); + return 0; +} + +static void NAttrSetFlag(ntfs_attr *na, FILE_ATTR_FLAGS flag) +{ + if (na->type == AT_DATA && na->name == AT_UNNAMED) + na->ni->flags |= flag; + else + ntfs_log_trace("Denied setting flag %d for not unnamed data " + "attribute\n", flag); +} + +static void NAttrClearFlag(ntfs_attr *na, FILE_ATTR_FLAGS flag) +{ + if (na->type == AT_DATA && na->name == AT_UNNAMED) + na->ni->flags &= ~flag; +} + +#define GenNAttrIno(func_name, flag) \ +int NAttr##func_name(ntfs_attr *na) { return NAttrFlag (na, flag); } \ +void NAttrSet##func_name(ntfs_attr *na) { NAttrSetFlag (na, flag); } \ +void NAttrClear##func_name(ntfs_attr *na){ NAttrClearFlag(na, flag); } + +GenNAttrIno(Compressed, FILE_ATTR_COMPRESSED) +GenNAttrIno(Encrypted, FILE_ATTR_ENCRYPTED) +GenNAttrIno(Sparse, FILE_ATTR_SPARSE_FILE) + +/** + * ntfs_get_attribute_value_length - Find the length of an attribute + * @a: + * + * Description... + * + * Returns: + */ +s64 ntfs_get_attribute_value_length(const ATTR_RECORD *a) +{ + if (!a) { + errno = EINVAL; + return 0; + } + errno = 0; + if (a->non_resident) + return sle64_to_cpu(a->data_size); + + return (s64)le32_to_cpu(a->value_length); +} + +/** + * ntfs_get_attribute_value - Get a copy of an attribute + * @vol: + * @a: + * @b: + * + * Description... + * + * Returns: + */ +s64 ntfs_get_attribute_value(const ntfs_volume *vol, + const ATTR_RECORD *a, u8 *b) +{ + runlist *rl; + s64 total, r; + int i; + + /* Sanity checks. */ + if (!vol || !a || !b) { + errno = EINVAL; + return 0; + } + /* Complex attribute? */ + /* + * Ignore the flags in case they are not zero for an attribute list + * attribute. Windows does not complain about invalid flags and chkdsk + * does not detect or fix them so we need to cope with it, too. + */ + if (a->type != AT_ATTRIBUTE_LIST && a->flags) { + ntfs_log_error("Non-zero (%04x) attribute flags. Cannot handle " + "this yet.\n", le16_to_cpu(a->flags)); + errno = EOPNOTSUPP; + return 0; + } + if (!a->non_resident) { + /* Attribute is resident. */ + + /* Sanity check. */ + if (le32_to_cpu(a->value_length) + le16_to_cpu(a->value_offset) + > le32_to_cpu(a->length)) { + return 0; + } + + memcpy(b, (const char*)a + le16_to_cpu(a->value_offset), + le32_to_cpu(a->value_length)); + errno = 0; + return (s64)le32_to_cpu(a->value_length); + } + + /* Attribute is not resident. */ + + /* If no data, return 0. */ + if (!(a->data_size)) { + errno = 0; + return 0; + } + /* + * FIXME: What about attribute lists?!? (AIA) + */ + /* Decompress the mapping pairs array into a runlist. */ + rl = ntfs_mapping_pairs_decompress(vol, a, NULL); + if (!rl) { + errno = EINVAL; + return 0; + } + /* + * FIXED: We were overflowing here in a nasty fashion when we + * reach the last cluster in the runlist as the buffer will + * only be big enough to hold data_size bytes while we are + * reading in allocated_size bytes which is usually larger + * than data_size, since the actual data is unlikely to have a + * size equal to a multiple of the cluster size! + * FIXED2: We were also overflowing here in the same fashion + * when the data_size was more than one run smaller than the + * allocated size which happens with Windows XP sometimes. + */ + /* Now load all clusters in the runlist into b. */ + for (i = 0, total = 0; rl[i].length; i++) { + if (total + (rl[i].length << vol->cluster_size_bits) >= + sle64_to_cpu(a->data_size)) { + unsigned char *intbuf = NULL; + /* + * We have reached the last run so we were going to + * overflow when executing the ntfs_pread() which is + * BAAAAAAAD! + * Temporary fix: + * Allocate a new buffer with size: + * rl[i].length << vol->cluster_size_bits, do the + * read into our buffer, then memcpy the correct + * amount of data into the caller supplied buffer, + * free our buffer, and continue. + * We have reached the end of data size so we were + * going to overflow in the same fashion. + * Temporary fix: same as above. + */ + intbuf = ntfs_malloc(rl[i].length << vol->cluster_size_bits); + if (!intbuf) { + free(rl); + return 0; + } + /* + * FIXME: If compressed file: Only read if lcn != -1. + * Otherwise, we are dealing with a sparse run and we + * just memset the user buffer to 0 for the length of + * the run, which should be 16 (= compression unit + * size). + * FIXME: Really only when file is compressed, or can + * we have sparse runs in uncompressed files as well? + * - Yes we can, in sparse files! But not necessarily + * size of 16, just run length. + */ + r = ntfs_pread(vol->dev, rl[i].lcn << + vol->cluster_size_bits, rl[i].length << + vol->cluster_size_bits, intbuf); + if (r != rl[i].length << vol->cluster_size_bits) { +#define ESTR "Error reading attribute value" + if (r == -1) + ntfs_log_perror(ESTR); + else if (r < rl[i].length << + vol->cluster_size_bits) { + ntfs_log_debug(ESTR ": Ran out of input data.\n"); + errno = EIO; + } else { + ntfs_log_debug(ESTR ": unknown error\n"); + errno = EIO; + } +#undef ESTR + free(rl); + free(intbuf); + return 0; + } + memcpy(b + total, intbuf, sle64_to_cpu(a->data_size) - + total); + free(intbuf); + total = sle64_to_cpu(a->data_size); + break; + } + /* + * FIXME: If compressed file: Only read if lcn != -1. + * Otherwise, we are dealing with a sparse run and we just + * memset the user buffer to 0 for the length of the run, which + * should be 16 (= compression unit size). + * FIXME: Really only when file is compressed, or can + * we have sparse runs in uncompressed files as well? + * - Yes we can, in sparse files! But not necessarily size of + * 16, just run length. + */ + r = ntfs_pread(vol->dev, rl[i].lcn << vol->cluster_size_bits, + rl[i].length << vol->cluster_size_bits, + b + total); + if (r != rl[i].length << vol->cluster_size_bits) { +#define ESTR "Error reading attribute value" + if (r == -1) + ntfs_log_perror(ESTR); + else if (r < rl[i].length << vol->cluster_size_bits) { + ntfs_log_debug(ESTR ": Ran out of input data.\n"); + errno = EIO; + } else { + ntfs_log_debug(ESTR ": unknown error\n"); + errno = EIO; + } +#undef ESTR + free(rl); + return 0; + } + total += r; + } + free(rl); + return total; +} + +/* Already cleaned up code below, but still look for FIXME:... */ + +/** + * __ntfs_attr_init - primary initialization of an ntfs attribute structure + * @na: ntfs attribute to initialize + * @ni: ntfs inode with which to initialize the ntfs attribute + * @type: attribute type + * @name: attribute name in little endian Unicode or NULL + * @name_len: length of attribute @name in Unicode characters (if @name given) + * + * Initialize the ntfs attribute @na with @ni, @type, @name, and @name_len. + */ +static void __ntfs_attr_init(ntfs_attr *na, ntfs_inode *ni, + const ATTR_TYPES type, ntfschar *name, const u32 name_len) +{ + na->rl = NULL; + na->ni = ni; + na->type = type; + na->name = name; + if (name) + na->name_len = name_len; + else + na->name_len = 0; +} + +/** + * ntfs_attr_init - initialize an ntfs_attr with data sizes and status + * @na: + * @non_resident: + * @compressed: + * @encrypted: + * @sparse: + * @allocated_size: + * @data_size: + * @initialized_size: + * @compressed_size: + * @compression_unit: + * + * Final initialization for an ntfs attribute. + */ +void ntfs_attr_init(ntfs_attr *na, const BOOL non_resident, + const ATTR_FLAGS data_flags, + const BOOL encrypted, const BOOL sparse, + const s64 allocated_size, const s64 data_size, + const s64 initialized_size, const s64 compressed_size, + const u8 compression_unit) +{ + if (!NAttrInitialized(na)) { + na->data_flags = data_flags; + if (non_resident) + NAttrSetNonResident(na); + if (data_flags & ATTR_COMPRESSION_MASK) + NAttrSetCompressed(na); + if (encrypted) + NAttrSetEncrypted(na); + if (sparse) + NAttrSetSparse(na); + na->allocated_size = allocated_size; + na->data_size = data_size; + na->initialized_size = initialized_size; + if ((data_flags & ATTR_COMPRESSION_MASK) || sparse) { + ntfs_volume *vol = na->ni->vol; + + na->compressed_size = compressed_size; + na->compression_block_clusters = 1 << compression_unit; + na->compression_block_size = 1 << (compression_unit + + vol->cluster_size_bits); + na->compression_block_size_bits = ffs( + na->compression_block_size) - 1; + } + NAttrSetInitialized(na); + } +} + +/** + * ntfs_attr_open - open an ntfs attribute for access + * @ni: open ntfs inode in which the ntfs attribute resides + * @type: attribute type + * @name: attribute name in little endian Unicode or AT_UNNAMED or NULL + * @name_len: length of attribute @name in Unicode characters (if @name given) + * + * Allocate a new ntfs attribute structure, initialize it with @ni, @type, + * @name, and @name_len, then return it. Return NULL on error with + * errno set to the error code. + * + * If @name is AT_UNNAMED look specifically for an unnamed attribute. If you + * do not care whether the attribute is named or not set @name to NULL. In + * both those cases @name_len is not used at all. + */ +ntfs_attr *ntfs_attr_open(ntfs_inode *ni, const ATTR_TYPES type, + ntfschar *name, u32 name_len) +{ + ntfs_attr_search_ctx *ctx; + ntfs_attr *na = NULL; + ntfschar *newname = NULL; + ATTR_RECORD *a; + BOOL cs; + + ntfs_log_enter("Entering for inode %lld, attr 0x%x.\n", + (unsigned long long)ni->mft_no, type); + + if (!ni || !ni->vol || !ni->mrec) { + errno = EINVAL; + goto out; + } + na = ntfs_calloc(sizeof(ntfs_attr)); + if (!na) + goto out; + if (name && name != AT_UNNAMED && name != NTFS_INDEX_I30) { + name = ntfs_ucsndup(name, name_len); + if (!name) + goto err_out; + newname = name; + } + + ctx = ntfs_attr_get_search_ctx(ni, NULL); + if (!ctx) + goto err_out; + + if (ntfs_attr_lookup(type, name, name_len, 0, 0, NULL, 0, ctx)) + goto put_err_out; + + a = ctx->attr; + + if (!name) { + if (a->name_length) { + name = ntfs_ucsndup((ntfschar*)((u8*)a + le16_to_cpu( + a->name_offset)), a->name_length); + if (!name) + goto put_err_out; + newname = name; + name_len = a->name_length; + } else { + name = AT_UNNAMED; + name_len = 0; + } + } + + __ntfs_attr_init(na, ni, type, name, name_len); + + /* + * Wipe the flags in case they are not zero for an attribute list + * attribute. Windows does not complain about invalid flags and chkdsk + * does not detect or fix them so we need to cope with it, too. + */ + if (type == AT_ATTRIBUTE_LIST) + a->flags = 0; + + if ((type == AT_DATA) && !a->initialized_size) { + /* + * Define/redefine the compression state if stream is + * empty, based on the compression mark on parent + * directory (for unnamed data streams) or on current + * inode (for named data streams). The compression mark + * may change any time, the compression state can only + * change when stream is wiped out. + */ + a->flags &= ~ATTR_COMPRESSION_MASK; + if ((na->ni->flags & FILE_ATTR_COMPRESSED) + && (ni->vol->cluster_size <= MAX_COMPRESSION_CLUSTER_SIZE)) + a->flags |= ATTR_IS_COMPRESSED; + } + + cs = a->flags & (ATTR_IS_COMPRESSED | ATTR_IS_SPARSE); + + if (na->type == AT_DATA && na->name == AT_UNNAMED && + ((!(a->flags & ATTR_IS_SPARSE) != !NAttrSparse(na)) || + (!(a->flags & ATTR_IS_ENCRYPTED) != !NAttrEncrypted(na)))) { + errno = EIO; + ntfs_log_perror("Inode %lld has corrupt attribute flags " + "(0x%x <> 0x%x)",(unsigned long long)ni->mft_no, + a->flags, na->ni->flags); + goto put_err_out; + } + + if (a->non_resident) { + if ((a->flags & ATTR_COMPRESSION_MASK) + && !a->compression_unit) { + errno = EIO; + ntfs_log_perror("Compressed inode %lld attr 0x%x has " + "no compression unit", + (unsigned long long)ni->mft_no, type); + goto put_err_out; + } + ntfs_attr_init(na, TRUE, a->flags, + a->flags & ATTR_IS_ENCRYPTED, + a->flags & ATTR_IS_SPARSE, + sle64_to_cpu(a->allocated_size), + sle64_to_cpu(a->data_size), + sle64_to_cpu(a->initialized_size), + cs ? sle64_to_cpu(a->compressed_size) : 0, + cs ? a->compression_unit : 0); + } else { + s64 l = le32_to_cpu(a->value_length); + ntfs_attr_init(na, FALSE, a->flags, + a->flags & ATTR_IS_ENCRYPTED, + a->flags & ATTR_IS_SPARSE, (l + 7) & ~7, l, l, + cs ? (l + 7) & ~7 : 0, 0); + } + ntfs_attr_put_search_ctx(ctx); +out: + ntfs_log_leave("\n"); + return na; + +put_err_out: + ntfs_attr_put_search_ctx(ctx); +err_out: + free(newname); + free(na); + na = NULL; + goto out; +} + +/** + * ntfs_attr_close - free an ntfs attribute structure + * @na: ntfs attribute structure to free + * + * Release all memory associated with the ntfs attribute @na and then release + * @na itself. + */ +void ntfs_attr_close(ntfs_attr *na) +{ + if (!na) + return; + if (NAttrNonResident(na) && na->rl) + free(na->rl); + /* Don't release if using an internal constant. */ + if (na->name != AT_UNNAMED && na->name != NTFS_INDEX_I30 + && na->name != STREAM_SDS) + free(na->name); + free(na); +} + +/** + * ntfs_attr_map_runlist - map (a part of) a runlist of an ntfs attribute + * @na: ntfs attribute for which to map (part of) a runlist + * @vcn: map runlist part containing this vcn + * + * Map the part of a runlist containing the @vcn of the ntfs attribute @na. + * + * Return 0 on success and -1 on error with errno set to the error code. + */ +int ntfs_attr_map_runlist(ntfs_attr *na, VCN vcn) +{ + LCN lcn; + ntfs_attr_search_ctx *ctx; + + ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x, vcn 0x%llx.\n", + (unsigned long long)na->ni->mft_no, na->type, (long long)vcn); + + lcn = ntfs_rl_vcn_to_lcn(na->rl, vcn); + if (lcn >= 0 || lcn == LCN_HOLE || lcn == LCN_ENOENT) + return 0; + + ctx = ntfs_attr_get_search_ctx(na->ni, NULL); + if (!ctx) + return -1; + + /* Find the attribute in the mft record. */ + if (!ntfs_attr_lookup(na->type, na->name, na->name_len, CASE_SENSITIVE, + vcn, NULL, 0, ctx)) { + runlist_element *rl; + + /* Decode the runlist. */ + rl = ntfs_mapping_pairs_decompress(na->ni->vol, ctx->attr, + na->rl); + if (rl) { + na->rl = rl; + ntfs_attr_put_search_ctx(ctx); + return 0; + } + } + + ntfs_attr_put_search_ctx(ctx); + return -1; +} + +/** + * ntfs_attr_map_whole_runlist - map the whole runlist of an ntfs attribute + * @na: ntfs attribute for which to map the runlist + * + * Map the whole runlist of the ntfs attribute @na. For an attribute made up + * of only one attribute extent this is the same as calling + * ntfs_attr_map_runlist(na, 0) but for an attribute with multiple extents this + * will map the runlist fragments from each of the extents thus giving access + * to the entirety of the disk allocation of an attribute. + * + * Return 0 on success and -1 on error with errno set to the error code. + */ +int ntfs_attr_map_whole_runlist(ntfs_attr *na) +{ + VCN next_vcn, last_vcn, highest_vcn; + ntfs_attr_search_ctx *ctx; + ntfs_volume *vol = na->ni->vol; + ATTR_RECORD *a; + int ret = -1; + + ntfs_log_enter("Entering for inode %llu, attr 0x%x.\n", + (unsigned long long)na->ni->mft_no, na->type); + + ctx = ntfs_attr_get_search_ctx(na->ni, NULL); + if (!ctx) + goto out; + + /* Map all attribute extents one by one. */ + next_vcn = last_vcn = highest_vcn = 0; + a = NULL; + while (1) { + runlist_element *rl; + + int not_mapped = 0; + if (ntfs_rl_vcn_to_lcn(na->rl, next_vcn) == LCN_RL_NOT_MAPPED) + not_mapped = 1; + + if (ntfs_attr_lookup(na->type, na->name, na->name_len, + CASE_SENSITIVE, next_vcn, NULL, 0, ctx)) + break; + + a = ctx->attr; + + if (not_mapped) { + /* Decode the runlist. */ + rl = ntfs_mapping_pairs_decompress(na->ni->vol, + a, na->rl); + if (!rl) + goto err_out; + na->rl = rl; + } + + /* Are we in the first extent? */ + if (!next_vcn) { + if (a->lowest_vcn) { + errno = EIO; + ntfs_log_perror("First extent of inode %llu " + "attribute has non-zero lowest_vcn", + (unsigned long long)na->ni->mft_no); + goto err_out; + } + /* Get the last vcn in the attribute. */ + last_vcn = sle64_to_cpu(a->allocated_size) >> + vol->cluster_size_bits; + } + + /* Get the lowest vcn for the next extent. */ + highest_vcn = sle64_to_cpu(a->highest_vcn); + next_vcn = highest_vcn + 1; + + /* Only one extent or error, which we catch below. */ + if (next_vcn <= 0) { + errno = ENOENT; + break; + } + + /* Avoid endless loops due to corruption. */ + if (next_vcn < sle64_to_cpu(a->lowest_vcn)) { + errno = EIO; + ntfs_log_perror("Inode %llu has corrupt attribute list", + (unsigned long long)na->ni->mft_no); + goto err_out; + } + } + if (!a) { + ntfs_log_perror("Couldn't find attribute for runlist mapping"); + goto err_out; + } + if (highest_vcn && highest_vcn != last_vcn - 1) { + errno = EIO; + ntfs_log_perror("Failed to load full runlist: inode: %llu " + "highest_vcn: 0x%llx last_vcn: 0x%llx", + (unsigned long long)na->ni->mft_no, + (long long)highest_vcn, (long long)last_vcn); + goto err_out; + } + if (errno == ENOENT) + ret = 0; +err_out: + ntfs_attr_put_search_ctx(ctx); +out: + ntfs_log_leave("\n"); + return ret; +} + +/** + * ntfs_attr_vcn_to_lcn - convert a vcn into a lcn given an ntfs attribute + * @na: ntfs attribute whose runlist to use for conversion + * @vcn: vcn to convert + * + * Convert the virtual cluster number @vcn of an attribute into a logical + * cluster number (lcn) of a device using the runlist @na->rl to map vcns to + * their corresponding lcns. + * + * If the @vcn is not mapped yet, attempt to map the attribute extent + * containing the @vcn and retry the vcn to lcn conversion. + * + * Since lcns must be >= 0, we use negative return values with special meaning: + * + * Return value Meaning / Description + * ========================================== + * -1 = LCN_HOLE Hole / not allocated on disk. + * -3 = LCN_ENOENT There is no such vcn in the attribute. + * -4 = LCN_EINVAL Input parameter error. + * -5 = LCN_EIO Corrupt fs, disk i/o error, or not enough memory. + */ +LCN ntfs_attr_vcn_to_lcn(ntfs_attr *na, const VCN vcn) +{ + LCN lcn; + BOOL is_retry = FALSE; + + if (!na || !NAttrNonResident(na) || vcn < 0) + return (LCN)LCN_EINVAL; + + ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x.\n", (unsigned long + long)na->ni->mft_no, na->type); +retry: + /* Convert vcn to lcn. If that fails map the runlist and retry once. */ + lcn = ntfs_rl_vcn_to_lcn(na->rl, vcn); + if (lcn >= 0) + return lcn; + if (!is_retry && !ntfs_attr_map_runlist(na, vcn)) { + is_retry = TRUE; + goto retry; + } + /* + * If the attempt to map the runlist failed, or we are getting + * LCN_RL_NOT_MAPPED despite having mapped the attribute extent + * successfully, something is really badly wrong... + */ + if (!is_retry || lcn == (LCN)LCN_RL_NOT_MAPPED) + return (LCN)LCN_EIO; + /* lcn contains the appropriate error code. */ + return lcn; +} + +/** + * ntfs_attr_find_vcn - find a vcn in the runlist of an ntfs attribute + * @na: ntfs attribute whose runlist to search + * @vcn: vcn to find + * + * Find the virtual cluster number @vcn in the runlist of the ntfs attribute + * @na and return the the address of the runlist element containing the @vcn. + * + * Note you need to distinguish between the lcn of the returned runlist + * element being >= 0 and LCN_HOLE. In the later case you have to return zeroes + * on read and allocate clusters on write. You need to update the runlist, the + * attribute itself as well as write the modified mft record to disk. + * + * If there is an error return NULL with errno set to the error code. The + * following error codes are defined: + * EINVAL Input parameter error. + * ENOENT There is no such vcn in the runlist. + * ENOMEM Not enough memory. + * EIO I/O error or corrupt metadata. + */ +runlist_element *ntfs_attr_find_vcn(ntfs_attr *na, const VCN vcn) +{ + runlist_element *rl; + BOOL is_retry = FALSE; + + if (!na || !NAttrNonResident(na) || vcn < 0) { + errno = EINVAL; + return NULL; + } + + ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x, vcn %llx\n", + (unsigned long long)na->ni->mft_no, na->type, + (long long)vcn); +retry: + rl = na->rl; + if (!rl) + goto map_rl; + if (vcn < rl[0].vcn) + goto map_rl; + while (rl->length) { + if (vcn < rl[1].vcn) { + if (rl->lcn >= (LCN)LCN_HOLE) + return rl; + break; + } + rl++; + } + switch (rl->lcn) { + case (LCN)LCN_RL_NOT_MAPPED: + goto map_rl; + case (LCN)LCN_ENOENT: + errno = ENOENT; + break; + case (LCN)LCN_EINVAL: + errno = EINVAL; + break; + default: + errno = EIO; + break; + } + return NULL; +map_rl: + /* The @vcn is in an unmapped region, map the runlist and retry. */ + if (!is_retry && !ntfs_attr_map_runlist(na, vcn)) { + is_retry = TRUE; + goto retry; + } + /* + * If we already retried or the mapping attempt failed something has + * gone badly wrong. EINVAL and ENOENT coming from a failed mapping + * attempt are equivalent to errors for us as they should not happen + * in our code paths. + */ + if (is_retry || errno == EINVAL || errno == ENOENT) + errno = EIO; + return NULL; +} + +/** + * ntfs_attr_pread_i - see description at ntfs_attr_pread() + */ +static s64 ntfs_attr_pread_i(ntfs_attr *na, const s64 pos, s64 count, void *b) +{ + s64 br, to_read, ofs, total, total2, max_read, max_init; + ntfs_volume *vol; + runlist_element *rl; + u16 efs_padding_length; + + /* Sanity checking arguments is done in ntfs_attr_pread(). */ + + if ((na->data_flags & ATTR_COMPRESSION_MASK) && NAttrNonResident(na)) { + if ((na->data_flags & ATTR_COMPRESSION_MASK) + == ATTR_IS_COMPRESSED) + return ntfs_compressed_attr_pread(na, pos, count, b); + else { + /* compression mode not supported */ + errno = EOPNOTSUPP; + return -1; + } + } + /* + * Encrypted non-resident attributes are not supported. We return + * access denied, which is what Windows NT4 does, too. + * However, allow if mounted with efs_raw option + */ + vol = na->ni->vol; + if (!vol->efs_raw && NAttrEncrypted(na) && NAttrNonResident(na)) { + errno = EACCES; + return -1; + } + + if (!count) + return 0; + /* + * Truncate reads beyond end of attribute, + * but round to next 512 byte boundary for encrypted + * attributes with efs_raw mount option + */ + max_read = na->data_size; + max_init = na->initialized_size; + if (na->ni->vol->efs_raw + && (na->data_flags & ATTR_IS_ENCRYPTED) + && NAttrNonResident(na)) { + if (na->data_size != na->initialized_size) { + ntfs_log_error("uninitialized encrypted file not supported\n"); + errno = EINVAL; + return -1; + } + max_init = max_read = ((na->data_size + 511) & ~511) + 2; + } + if (pos + count > max_read) { + if (pos >= max_read) + return 0; + count = max_read - pos; + } + /* If it is a resident attribute, get the value from the mft record. */ + if (!NAttrNonResident(na)) { + ntfs_attr_search_ctx *ctx; + char *val; + + ctx = ntfs_attr_get_search_ctx(na->ni, NULL); + if (!ctx) + return -1; + if (ntfs_attr_lookup(na->type, na->name, na->name_len, 0, + 0, NULL, 0, ctx)) { +res_err_out: + ntfs_attr_put_search_ctx(ctx); + return -1; + } + val = (char*)ctx->attr + le16_to_cpu(ctx->attr->value_offset); + if (val < (char*)ctx->attr || val + + le32_to_cpu(ctx->attr->value_length) > + (char*)ctx->mrec + vol->mft_record_size) { + errno = EIO; + ntfs_log_perror("%s: Sanity check failed", __FUNCTION__); + goto res_err_out; + } + memcpy(b, val + pos, count); + ntfs_attr_put_search_ctx(ctx); + return count; + } + total = total2 = 0; + /* Zero out reads beyond initialized size. */ + if (pos + count > max_init) { + if (pos >= max_init) { + memset(b, 0, count); + return count; + } + total2 = pos + count - max_init; + count -= total2; + memset((u8*)b + count, 0, total2); + } + /* + * for encrypted non-resident attributes with efs_raw set + * the last two bytes aren't read from disk but contain + * the number of padding bytes so original size can be + * restored + */ + if (na->ni->vol->efs_raw && + (na->data_flags & ATTR_IS_ENCRYPTED) && + ((pos + count) > max_init-2)) { + efs_padding_length = 511 - ((na->data_size - 1) & 511); + if (pos+count == max_init) { + if (count == 1) { + *((u8*)b+count-1) = (u8)(efs_padding_length >> 8); + count--; + total2++; + } else { + *(u16*)((u8*)b+count-2) = cpu_to_le16(efs_padding_length); + count -= 2; + total2 +=2; + } + } else { + *((u8*)b+count-1) = (u8)(efs_padding_length & 0xff); + count--; + total2++; + } + } + + /* Find the runlist element containing the vcn. */ + rl = ntfs_attr_find_vcn(na, pos >> vol->cluster_size_bits); + if (!rl) { + /* + * If the vcn is not present it is an out of bounds read. + * However, we already truncated the read to the data_size, + * so getting this here is an error. + */ + if (errno == ENOENT) { + errno = EIO; + ntfs_log_perror("%s: Failed to find VCN #1", __FUNCTION__); + } + return -1; + } + /* + * Gather the requested data into the linear destination buffer. Note, + * a partial final vcn is taken care of by the @count capping of read + * length. + */ + ofs = pos - (rl->vcn << vol->cluster_size_bits); + for (; count; rl++, ofs = 0) { + if (rl->lcn == LCN_RL_NOT_MAPPED) { + rl = ntfs_attr_find_vcn(na, rl->vcn); + if (!rl) { + if (errno == ENOENT) { + errno = EIO; + ntfs_log_perror("%s: Failed to find VCN #2", + __FUNCTION__); + } + goto rl_err_out; + } + /* Needed for case when runs merged. */ + ofs = pos + total - (rl->vcn << vol->cluster_size_bits); + } + if (!rl->length) { + errno = EIO; + ntfs_log_perror("%s: Zero run length", __FUNCTION__); + goto rl_err_out; + } + if (rl->lcn < (LCN)0) { + if (rl->lcn != (LCN)LCN_HOLE) { + ntfs_log_perror("%s: Bad run (%lld)", + __FUNCTION__, + (long long)rl->lcn); + goto rl_err_out; + } + /* It is a hole, just zero the matching @b range. */ + to_read = min(count, (rl->length << + vol->cluster_size_bits) - ofs); + memset(b, 0, to_read); + /* Update progress counters. */ + total += to_read; + count -= to_read; + b = (u8*)b + to_read; + continue; + } + /* It is a real lcn, read it into @dst. */ + to_read = min(count, (rl->length << vol->cluster_size_bits) - + ofs); +retry: + ntfs_log_trace("Reading %lld bytes from vcn %lld, lcn %lld, ofs" + " %lld.\n", (long long)to_read, (long long)rl->vcn, + (long long )rl->lcn, (long long)ofs); + br = ntfs_pread(vol->dev, (rl->lcn << vol->cluster_size_bits) + + ofs, to_read, b); + /* If everything ok, update progress counters and continue. */ + if (br > 0) { + total += br; + count -= br; + b = (u8*)b + br; + } + if (br == to_read) + continue; + /* If the syscall was interrupted, try again. */ + if (br == (s64)-1 && errno == EINTR) + goto retry; + if (total) + return total; + if (!br) + errno = EIO; + ntfs_log_perror("%s: ntfs_pread failed", __FUNCTION__); + return -1; + } + /* Finally, return the number of bytes read. */ + return total + total2; +rl_err_out: + if (total) + return total; + errno = EIO; + return -1; +} + +/** + * ntfs_attr_pread - read from an attribute specified by an ntfs_attr structure + * @na: ntfs attribute to read from + * @pos: byte position in the attribute to begin reading from + * @count: number of bytes to read + * @b: output data buffer + * + * This function will read @count bytes starting at offset @pos from the ntfs + * attribute @na into the data buffer @b. + * + * On success, return the number of successfully read bytes. If this number is + * lower than @count this means that the read reached end of file or that an + * error was encountered during the read so that the read is partial. 0 means + * end of file or nothing was read (also return 0 when @count is 0). + * + * On error and nothing has been read, return -1 with errno set appropriately + * to the return code of ntfs_pread(), or to EINVAL in case of invalid + * arguments. + */ +s64 ntfs_attr_pread(ntfs_attr *na, const s64 pos, s64 count, void *b) +{ + s64 ret; + + if (!na || !na->ni || !na->ni->vol || !b || pos < 0 || count < 0) { + errno = EINVAL; + ntfs_log_perror("%s: na=%p b=%p pos=%lld count=%lld", + __FUNCTION__, na, b, (long long)pos, + (long long)count); + return -1; + } + + ntfs_log_enter("Entering for inode %lld attr 0x%x pos %lld count " + "%lld\n", (unsigned long long)na->ni->mft_no, + na->type, (long long)pos, (long long)count); + + ret = ntfs_attr_pread_i(na, pos, count, b); + + ntfs_log_leave("\n"); + return ret; +} + +static int ntfs_attr_fill_zero(ntfs_attr *na, s64 pos, s64 count) +{ + char *buf; + s64 written, size, end = pos + count; + s64 ofsi; + const runlist_element *rli; + ntfs_volume *vol; + int ret = -1; + + ntfs_log_trace("pos %lld, count %lld\n", (long long)pos, + (long long)count); + + if (!na || pos < 0 || count < 0) { + errno = EINVAL; + goto err_out; + } + + buf = ntfs_calloc(NTFS_BUF_SIZE); + if (!buf) + goto err_out; + + rli = na->rl; + ofsi = 0; + vol = na->ni->vol; + while (pos < end) { + while (rli->length && (ofsi + (rli->length << + vol->cluster_size_bits) <= pos)) { + ofsi += (rli->length << vol->cluster_size_bits); + rli++; + } + size = min(end - pos, NTFS_BUF_SIZE); + written = ntfs_rl_pwrite(vol, rli, ofsi, pos, size, buf); + if (written <= 0) { + ntfs_log_perror("Failed to zero space"); + goto err_free; + } + pos += written; + } + + ret = 0; +err_free: + free(buf); +err_out: + return ret; +} + +static int ntfs_attr_fill_hole(ntfs_attr *na, s64 count, s64 *ofs, + runlist_element **rl, VCN *update_from) +{ + s64 to_write; + s64 need; + ntfs_volume *vol = na->ni->vol; + int eo, ret = -1; + runlist *rlc; + LCN lcn_seek_from = -1; + VCN cur_vcn, from_vcn; + + to_write = min(count, ((*rl)->length << vol->cluster_size_bits) - *ofs); + + cur_vcn = (*rl)->vcn; + from_vcn = (*rl)->vcn + (*ofs >> vol->cluster_size_bits); + + ntfs_log_trace("count: %lld, cur_vcn: %lld, from: %lld, to: %lld, ofs: " + "%lld\n", (long long)count, (long long)cur_vcn, + (long long)from_vcn, (long long)to_write, (long long)*ofs); + + /* Map whole runlist to be able update mapping pairs later. */ + if (ntfs_attr_map_whole_runlist(na)) + goto err_out; + + /* Restore @*rl, it probably get lost during runlist mapping. */ + *rl = ntfs_attr_find_vcn(na, cur_vcn); + if (!*rl) { + ntfs_log_error("Failed to find run after mapping runlist. " + "Please report to %s.\n", NTFS_DEV_LIST); + errno = EIO; + goto err_out; + } + + /* Search backwards to find the best lcn to start seek from. */ + rlc = *rl; + while (rlc->vcn) { + rlc--; + if (rlc->lcn >= 0) { + /* + * avoid fragmenting a compressed file + * Windows does not do that, and that may + * not be desirable for files which can + * be updated + */ + if (na->data_flags & ATTR_COMPRESSION_MASK) + lcn_seek_from = rlc->lcn + rlc->length; + else + lcn_seek_from = rlc->lcn + (from_vcn - rlc->vcn); + break; + } + } + if (lcn_seek_from == -1) { + /* Backwards search failed, search forwards. */ + rlc = *rl; + while (rlc->length) { + rlc++; + if (rlc->lcn >= 0) { + lcn_seek_from = rlc->lcn - (rlc->vcn - from_vcn); + if (lcn_seek_from < -1) + lcn_seek_from = -1; + break; + } + } + } + + need = ((*ofs + to_write - 1) >> vol->cluster_size_bits) + + 1 + (*rl)->vcn - from_vcn; + if ((na->data_flags & ATTR_COMPRESSION_MASK) + && (need < na->compression_block_clusters)) { + /* + * for a compressed file, be sure to allocate the full hole. + * We may need space to decompress existing compressed data. + */ + rlc = ntfs_cluster_alloc(vol, (*rl)->vcn, (*rl)->length, + lcn_seek_from, DATA_ZONE); + } else + rlc = ntfs_cluster_alloc(vol, from_vcn, need, + lcn_seek_from, DATA_ZONE); + if (!rlc) + goto err_out; + + *rl = ntfs_runlists_merge(na->rl, rlc); + /* + * For a compressed attribute, we must be sure there is an + * available entry, so reserve it before it gets too late. + */ + if (*rl && (na->data_flags & ATTR_COMPRESSION_MASK)) + *rl = ntfs_rl_extend(*rl,1); + if (!*rl) { + eo = errno; + ntfs_log_perror("Failed to merge runlists"); + if (ntfs_cluster_free_from_rl(vol, rlc)) { + ntfs_log_perror("Failed to free hot clusters. " + "Please run chkdsk /f"); + } + errno = eo; + goto err_out; + } + na->rl = *rl; + if (*update_from == -1) + *update_from = from_vcn; + *rl = ntfs_attr_find_vcn(na, cur_vcn); + if (!*rl) { + /* + * It's definitely a BUG, if we failed to find @cur_vcn, because + * we missed it during instantiating of the hole. + */ + ntfs_log_error("Failed to find run after hole instantiation. " + "Please report to %s.\n", NTFS_DEV_LIST); + errno = EIO; + goto err_out; + } + /* If leaved part of the hole go to the next run. */ + if ((*rl)->lcn < 0) + (*rl)++; + /* Now LCN shoudn't be less than 0. */ + if ((*rl)->lcn < 0) { + ntfs_log_error("BUG! LCN is lesser than 0. " + "Please report to the %s.\n", NTFS_DEV_LIST); + errno = EIO; + goto err_out; + } + if (*ofs) { + /* Clear non-sparse region from @cur_vcn to @*ofs. */ + if (ntfs_attr_fill_zero(na, cur_vcn << vol->cluster_size_bits, + *ofs)) + goto err_out; + } + if ((*rl)->vcn < cur_vcn) { + /* + * Clusters that replaced hole are merged with + * previous run, so we need to update offset. + */ + *ofs += (cur_vcn - (*rl)->vcn) << vol->cluster_size_bits; + } + if ((*rl)->vcn > cur_vcn) { + /* + * We left part of the hole, so we need to update offset + */ + *ofs -= ((*rl)->vcn - cur_vcn) << vol->cluster_size_bits; + } + + ret = 0; +err_out: + return ret; +} + +static int stuff_hole(ntfs_attr *na, const s64 pos); + +/** + * ntfs_attr_pwrite - positioned write to an ntfs attribute + * @na: ntfs attribute to write to + * @pos: position in the attribute to write to + * @count: number of bytes to write + * @b: data buffer to write to disk + * + * This function will write @count bytes from data buffer @b to ntfs attribute + * @na at position @pos. + * + * On success, return the number of successfully written bytes. If this number + * is lower than @count this means that an error was encountered during the + * write so that the write is partial. 0 means nothing was written (also return + * 0 when @count is 0). + * + * On error and nothing has been written, return -1 with errno set + * appropriately to the return code of ntfs_pwrite(), or to EINVAL in case of + * invalid arguments. + */ +s64 ntfs_attr_pwrite(ntfs_attr *na, const s64 pos, s64 count, const void *b) +{ + s64 written, to_write, ofs, old_initialized_size, old_data_size; + s64 total = 0; + VCN update_from = -1; + ntfs_volume *vol; + s64 fullcount; + ntfs_attr_search_ctx *ctx = NULL; + runlist_element *rl; + s64 hole_end; + int eo; + int compressed_part; + struct { + unsigned int undo_initialized_size : 1; + unsigned int undo_data_size : 1; + } need_to = { 0, 0 }; + BOOL makingnonresident = FALSE; + BOOL wasnonresident = FALSE; + BOOL compressed; + + ntfs_log_enter("Entering for inode %lld, attr 0x%x, pos 0x%llx, count " + "0x%llx.\n", (long long)na->ni->mft_no, na->type, + (long long)pos, (long long)count); + + if (!na || !na->ni || !na->ni->vol || !b || pos < 0 || count < 0) { + errno = EINVAL; + ntfs_log_perror("%s", __FUNCTION__); + goto errno_set; + } + vol = na->ni->vol; + compressed = (na->data_flags & ATTR_COMPRESSION_MASK) + != const_cpu_to_le16(0); + /* + * Encrypted attributes are only supported in raw mode. We return + * access denied, which is what Windows NT4 does, too. + * Moreover a file cannot be both encrypted and compressed. + */ + if ((na->data_flags & ATTR_IS_ENCRYPTED) + && (compressed || !vol->efs_raw)) { + errno = EACCES; + goto errno_set; + } + /* + * Fill the gap, when writing beyond the end of a compressed + * file. This will make recursive calls + */ + if (compressed + && (na->type == AT_DATA) + && (pos > na->initialized_size) + && stuff_hole(na,pos)) + goto errno_set; + /* If this is a compressed attribute it needs special treatment. */ + wasnonresident = NAttrNonResident(na) != 0; + makingnonresident = wasnonresident /* yes : already changed */ + && !pos && (count == na->initialized_size); + /* + * Writing to compressed files is currently restricted + * to appending data. However we have to accept + * recursive write calls to make the attribute non resident. + * These are writing at position 0 up to initialized_size. + * Compression is also restricted to data streams. + * Only ATTR_IS_COMPRESSED compression mode is supported. + */ + if (compressed + && ((na->type != AT_DATA) + || ((na->data_flags & ATTR_COMPRESSION_MASK) + != ATTR_IS_COMPRESSED) + || ((pos != na->initialized_size) + && (pos || (count != na->initialized_size))))) { + // TODO: Implement writing compressed attributes! (AIA) + errno = EOPNOTSUPP; + goto errno_set; + } + + if (!count) + goto out; + /* for a compressed file, get prepared to reserve a full block */ + fullcount = count; + /* If the write reaches beyond the end, extend the attribute. */ + old_data_size = na->data_size; + if (pos + count > na->data_size) { + if (ntfs_attr_truncate(na, pos + count)) { + ntfs_log_perror("Failed to enlarge attribute"); + goto errno_set; + } + /* resizing may change the compression mode */ + compressed = (na->data_flags & ATTR_COMPRESSION_MASK) + != const_cpu_to_le16(0); + need_to.undo_data_size = 1; + } + /* + * For compressed data, a single full block was allocated + * to deal with compression, possibly in a previous call. + * We are not able to process several blocks because + * some clusters are freed after compression and + * new allocations have to be done before proceeding, + * so truncate the requested count if needed (big buffers). + */ + if (compressed) { + fullcount = na->data_size - pos; + if (count > fullcount) + count = fullcount; + } + old_initialized_size = na->initialized_size; + /* If it is a resident attribute, write the data to the mft record. */ + if (!NAttrNonResident(na)) { + char *val; + + ctx = ntfs_attr_get_search_ctx(na->ni, NULL); + if (!ctx) + goto err_out; + if (ntfs_attr_lookup(na->type, na->name, na->name_len, 0, + 0, NULL, 0, ctx)) { + ntfs_log_perror("%s: lookup failed", __FUNCTION__); + goto err_out; + } + val = (char*)ctx->attr + le16_to_cpu(ctx->attr->value_offset); + if (val < (char*)ctx->attr || val + + le32_to_cpu(ctx->attr->value_length) > + (char*)ctx->mrec + vol->mft_record_size) { + errno = EIO; + ntfs_log_perror("%s: Sanity check failed", __FUNCTION__); + goto err_out; + } + memcpy(val + pos, b, count); + if (ntfs_mft_record_write(vol, ctx->ntfs_ino->mft_no, + ctx->mrec)) { + /* + * NOTE: We are in a bad state at this moment. We have + * dirtied the mft record but we failed to commit it to + * disk. Since we have read the mft record ok before, + * it is unlikely to fail writing it, so is ok to just + * return error here... (AIA) + */ + ntfs_log_perror("%s: failed to write mft record", __FUNCTION__); + goto err_out; + } + ntfs_attr_put_search_ctx(ctx); + total = count; + goto out; + } + + /* Handle writes beyond initialized_size. */ + if (pos + count > na->initialized_size) { + if (ntfs_attr_map_whole_runlist(na)) + goto err_out; + /* + * For a compressed attribute, we must be sure there is an + * available entry, and, when reopening a compressed file, + * we may need to split a hole. So reserve the entries + * before it gets too late. + */ + if (compressed) { + na->rl = ntfs_rl_extend(na->rl,2); + if (!na->rl) + goto err_out; + } + /* Set initialized_size to @pos + @count. */ + ctx = ntfs_attr_get_search_ctx(na->ni, NULL); + if (!ctx) + goto err_out; + if (ntfs_attr_lookup(na->type, na->name, na->name_len, 0, + 0, NULL, 0, ctx)) + goto err_out; + + /* If write starts beyond initialized_size, zero the gap. */ + if (pos > na->initialized_size) + if (ntfs_attr_fill_zero(na, na->initialized_size, + pos - na->initialized_size)) + goto err_out; + + ctx->attr->initialized_size = cpu_to_sle64(pos + count); + /* fix data_size for compressed files */ + if (compressed) + ctx->attr->data_size = ctx->attr->initialized_size; + if (ntfs_mft_record_write(vol, ctx->ntfs_ino->mft_no, + ctx->mrec)) { + /* + * Undo the change in the in-memory copy and send it + * back for writing. + */ + ctx->attr->initialized_size = + cpu_to_sle64(old_initialized_size); + ntfs_mft_record_write(vol, ctx->ntfs_ino->mft_no, + ctx->mrec); + goto err_out; + } + na->initialized_size = pos + count; +#if CACHE_NIDATA_SIZE + if (na->ni->mrec->flags & MFT_RECORD_IS_DIRECTORY + ? na->type == AT_INDEX_ROOT && na->name == NTFS_INDEX_I30 + : na->type == AT_DATA && na->name == AT_UNNAMED) { + na->ni->data_size = na->data_size; + na->ni->allocated_size = na->allocated_size; + set_nino_flag(na->ni,KnownSize); + } +#endif + ntfs_attr_put_search_ctx(ctx); + ctx = NULL; + /* + * NOTE: At this point the initialized_size in the mft record + * has been updated BUT there is random data on disk thus if + * we decide to abort, we MUST change the initialized_size + * again. + */ + need_to.undo_initialized_size = 1; + } + /* Find the runlist element containing the vcn. */ + rl = ntfs_attr_find_vcn(na, pos >> vol->cluster_size_bits); + if (!rl) { + /* + * If the vcn is not present it is an out of bounds write. + * However, we already extended the size of the attribute, + * so getting this here must be an error of some kind. + */ + if (errno == ENOENT) { + errno = EIO; + ntfs_log_perror("%s: Failed to find VCN #3", __FUNCTION__); + } + goto err_out; + } + ofs = pos - (rl->vcn << vol->cluster_size_bits); + /* + * Determine if there is compressed data in the current + * compression block (when appending to an existing file). + * If so, decompression will be needed, and the full block + * must be allocated to be identified as uncompressed. + * This comes in two variants, depending on whether + * compression has saved at least one cluster. + * The compressed size can never be over full size by + * more than 485 (maximum for 15 compression blocks + * compressed to 4098 and the last 3640 bytes compressed + * to 3640 + 3640/8 = 4095, with 15*2 + 4095 - 3640 = 485) + * This is less than the smallest cluster, so the hole is + * is never beyond the cluster next to the position of + * the first uncompressed byte to write. + */ + compressed_part = 0; + if (compressed) { + if ((rl->lcn == (LCN)LCN_HOLE) + && wasnonresident) { + if (rl->length < na->compression_block_clusters) + compressed_part + = na->compression_block_clusters + - rl->length; + else { + compressed_part + = na->compression_block_clusters; + if (rl->length > na->compression_block_clusters) { + rl[2].lcn = rl[1].lcn; + rl[2].vcn = rl[1].vcn; + rl[2].length = rl[1].length; + rl[1].vcn -= compressed_part; + rl[1].lcn = LCN_HOLE; + rl[1].length = compressed_part; + rl[0].length -= compressed_part; + ofs -= rl->length << vol->cluster_size_bits; + rl++; + } + } + /* normal hole filling will do later */ + } else + if ((rl->lcn >= 0) && (rl[1].lcn == (LCN)LCN_HOLE)) { + s64 xofs; + + if (wasnonresident) + compressed_part = na->compression_block_clusters + - rl[1].length; + rl++; + xofs = 0; + if (ntfs_attr_fill_hole(na, + rl->length << vol->cluster_size_bits, + &xofs, &rl, &update_from)) + goto err_out; + /* the fist allocated cluster was not merged */ + if (!xofs) + rl--; + } + } + /* + * Scatter the data from the linear data buffer to the volume. Note, a + * partial final vcn is taken care of by the @count capping of write + * length. + */ + for (hole_end = 0; count; rl++, ofs = 0, hole_end = 0) { + if (rl->lcn == LCN_RL_NOT_MAPPED) { + rl = ntfs_attr_find_vcn(na, rl->vcn); + if (!rl) { + if (errno == ENOENT) { + errno = EIO; + ntfs_log_perror("%s: Failed to find VCN" + " #4", __FUNCTION__); + } + goto rl_err_out; + } + /* Needed for case when runs merged. */ + ofs = pos + total - (rl->vcn << vol->cluster_size_bits); + } + if (!rl->length) { + errno = EIO; + ntfs_log_perror("%s: Zero run length", __FUNCTION__); + goto rl_err_out; + } + if (rl->lcn < (LCN)0) { + hole_end = rl->vcn + rl->length; + + if (rl->lcn != (LCN)LCN_HOLE) { + errno = EIO; + ntfs_log_perror("%s: Unexpected LCN (%lld)", + __FUNCTION__, + (long long)rl->lcn); + goto rl_err_out; + } + if (ntfs_attr_fill_hole(na, fullcount, &ofs, &rl, + &update_from)) + goto err_out; + } + if (compressed) { + while (rl->length + && (ofs >= (rl->length << vol->cluster_size_bits))) { + ofs -= rl->length << vol->cluster_size_bits; + rl++; + } + } + + /* It is a real lcn, write it to the volume. */ + to_write = min(count, (rl->length << vol->cluster_size_bits) - ofs); +retry: + ntfs_log_trace("Writing %lld bytes to vcn %lld, lcn %lld, ofs " + "%lld.\n", (long long)to_write, (long long)rl->vcn, + (long long)rl->lcn, (long long)ofs); + if (!NVolReadOnly(vol)) { + + s64 wpos = (rl->lcn << vol->cluster_size_bits) + ofs; + s64 wend = (rl->vcn << vol->cluster_size_bits) + ofs + to_write; + u32 bsize = vol->cluster_size; + /* Byte size needed to zero fill a cluster */ + s64 rounding = ((wend + bsize - 1) & ~(s64)(bsize - 1)) - wend; + /** + * Zero fill to cluster boundary if we're writing at the + * end of the attribute or into an ex-sparse cluster. + * This will cause the kernel not to seek and read disk + * blocks during write(2) to fill the end of the buffer + * which increases write speed by 2-10 fold typically. + * + * This is done even for compressed files, because + * data is generally first written uncompressed. + */ + if (rounding && ((wend == na->initialized_size) || + (wend < (hole_end << vol->cluster_size_bits)))){ + + char *cb; + + rounding += to_write; + + cb = ntfs_malloc(rounding); + if (!cb) + goto err_out; + + memcpy(cb, b, to_write); + memset(cb + to_write, 0, rounding - to_write); + + if (compressed) { + written = ntfs_compressed_pwrite(na, + rl, wpos, ofs, to_write, + rounding, b, compressed_part); + } else { + written = ntfs_pwrite(vol->dev, wpos, + rounding, cb); + if (written == rounding) + written = to_write; + } + + free(cb); + } else { + if (compressed) { + written = ntfs_compressed_pwrite(na, + rl, wpos, ofs, to_write, + to_write, b, compressed_part); + } else + written = ntfs_pwrite(vol->dev, wpos, + to_write, b); + } + } else + written = to_write; + /* If everything ok, update progress counters and continue. */ + if (written > 0) { + total += written; + count -= written; + fullcount -= written; + b = (const u8*)b + written; + } + if (written != to_write) { + /* Partial write cannot be dealt with, stop there */ + /* If the syscall was interrupted, try again. */ + if (written == (s64)-1 && errno == EINTR) + goto retry; + if (!written) + errno = EIO; + goto rl_err_out; + } + compressed_part = 0; + } +done: + if (ctx) + ntfs_attr_put_search_ctx(ctx); + /* Update mapping pairs if needed. */ + if ((update_from != -1) + || (compressed && !makingnonresident)) + if (ntfs_attr_update_mapping_pairs(na, 0 /*update_from*/)) { + /* + * FIXME: trying to recover by goto rl_err_out; + * could cause driver hang by infinite looping. + */ + total = -1; + goto out; + } +out: + ntfs_log_leave("\n"); + return total; +rl_err_out: + eo = errno; + if (total) { + if (need_to.undo_initialized_size) { + if (pos + total > na->initialized_size) + goto done; + /* + * TODO: Need to try to change initialized_size. If it + * succeeds goto done, otherwise goto err_out. (AIA) + */ + goto err_out; + } + goto done; + } + errno = eo; +err_out: + eo = errno; + if (need_to.undo_initialized_size) { + int err; + + err = 0; + if (!ctx) { + ctx = ntfs_attr_get_search_ctx(na->ni, NULL); + if (!ctx) + err = 1; + } else + ntfs_attr_reinit_search_ctx(ctx); + if (!err) { + err = ntfs_attr_lookup(na->type, na->name, + na->name_len, 0, 0, NULL, 0, ctx); + if (!err) { + na->initialized_size = old_initialized_size; + ctx->attr->initialized_size = cpu_to_sle64( + old_initialized_size); + err = ntfs_mft_record_write(vol, + ctx->ntfs_ino->mft_no, + ctx->mrec); + } + } + if (err) { + /* + * FIXME: At this stage could try to recover by filling + * old_initialized_size -> new_initialized_size with + * data or at least zeroes. (AIA) + */ + ntfs_log_error("Eeek! Failed to recover from error. " + "Leaving metadata in inconsistent " + "state! Run chkdsk!\n"); + } + } + if (ctx) + ntfs_attr_put_search_ctx(ctx); + /* Update mapping pairs if needed. */ + if (update_from != -1) + ntfs_attr_update_mapping_pairs(na, 0 /*update_from*/); + /* Restore original data_size if needed. */ + if (need_to.undo_data_size && ntfs_attr_truncate(na, old_data_size)) + ntfs_log_perror("Failed to restore data_size"); + errno = eo; +errno_set: + total = -1; + goto out; +} + +int ntfs_attr_pclose(ntfs_attr *na) +{ + s64 ofs; + int failed; + BOOL ok = TRUE; + VCN update_from = -1; + ntfs_volume *vol; + ntfs_attr_search_ctx *ctx = NULL; + runlist_element *rl; + int eo; + s64 hole; + int compressed_part; + BOOL compressed; + + ntfs_log_enter("Entering for inode 0x%llx, attr 0x%x.\n", + na->ni->mft_no, na->type); + + if (!na || !na->ni || !na->ni->vol) { + errno = EINVAL; + ntfs_log_perror("%s", __FUNCTION__); + goto errno_set; + } + vol = na->ni->vol; + compressed = (na->data_flags & ATTR_COMPRESSION_MASK) + != const_cpu_to_le16(0); + /* + * Encrypted non-resident attributes are not supported. We return + * access denied, which is what Windows NT4 does, too. + */ + if (NAttrEncrypted(na) && NAttrNonResident(na)) { + errno = EACCES; + goto errno_set; + } + /* If this is not a compressed attribute get out */ + /* same if it is resident */ + if (!compressed || !NAttrNonResident(na)) + goto out; + + /* + * For a compressed attribute, we must be sure there is an + * available entry, so reserve it before it gets too late. + */ + if (ntfs_attr_map_whole_runlist(na)) + goto err_out; + na->rl = ntfs_rl_extend(na->rl,1); + if (!na->rl) + goto err_out; + /* Find the runlist element containing the terminal vcn. */ + rl = ntfs_attr_find_vcn(na, (na->initialized_size - 1) >> vol->cluster_size_bits); + if (!rl) { + /* + * If the vcn is not present it is an out of bounds write. + * However, we have already written the last byte uncompressed, + * so getting this here must be an error of some kind. + */ + if (errno == ENOENT) { + errno = EIO; + ntfs_log_perror("%s: Failed to find VCN #5", __FUNCTION__); + } + goto err_out; + } + /* + * Scatter the data from the linear data buffer to the volume. Note, a + * partial final vcn is taken care of by the @count capping of write + * length. + */ + compressed_part = 0; + if ((rl->lcn >= 0) && (rl[1].lcn == (LCN)LCN_HOLE)) + compressed_part + = na->compression_block_clusters - rl[1].length; + else + if (rl->lcn == (LCN)LCN_HOLE) { + if (rl->length < na->compression_block_clusters) + compressed_part + = na->compression_block_clusters + - rl->length; + else + compressed_part + = na->compression_block_clusters; + } + /* done, if the last block set was compressed */ + if (compressed_part) + goto out; + + ofs = na->initialized_size - (rl->vcn << vol->cluster_size_bits); + + if (rl->lcn == LCN_RL_NOT_MAPPED) { + rl = ntfs_attr_find_vcn(na, rl->vcn); + if (!rl) { + if (errno == ENOENT) { + errno = EIO; + ntfs_log_perror("%s: Failed to find VCN" + " #6", __FUNCTION__); + } + goto rl_err_out; + } + /* Needed for case when runs merged. */ + ofs = na->initialized_size - (rl->vcn << vol->cluster_size_bits); + } + if (!rl->length) { + errno = EIO; + ntfs_log_perror("%s: Zero run length", __FUNCTION__); + goto rl_err_out; + } + if (rl->lcn < (LCN)0) { + hole = rl->vcn + rl->length; + if (rl->lcn != (LCN)LCN_HOLE) { + errno = EIO; + ntfs_log_perror("%s: Unexpected LCN (%lld)", + __FUNCTION__, + (long long)rl->lcn); + goto rl_err_out; + } + + if (ntfs_attr_fill_hole(na, (s64)0, &ofs, &rl, &update_from)) + goto err_out; + } + while (rl->length + && (ofs >= (rl->length << vol->cluster_size_bits))) { + ofs -= rl->length << vol->cluster_size_bits; + rl++; + } + +retry: + failed = 0; + if (!NVolReadOnly(vol)) { + failed = ntfs_compressed_close(na, rl, ofs); +#if CACHE_NIDATA_SIZE + if (na->ni->mrec->flags & MFT_RECORD_IS_DIRECTORY + ? na->type == AT_INDEX_ROOT && na->name == NTFS_INDEX_I30 + : na->type == AT_DATA && na->name == AT_UNNAMED) { + na->ni->data_size = na->data_size; + na->ni->allocated_size = na->allocated_size; + set_nino_flag(na->ni,KnownSize); + } +#endif + } + if (failed) { + /* If the syscall was interrupted, try again. */ + if (errno == EINTR) + goto retry; + else + goto rl_err_out; + } + if (ctx) + ntfs_attr_put_search_ctx(ctx); + /* Update mapping pairs if needed. */ + if (ntfs_attr_update_mapping_pairs(na, 0 /*update_from*/)) { + /* + * FIXME: trying to recover by goto rl_err_out; + * could cause driver hang by infinite looping. + */ + ok = FALSE; + goto out; + } +out: + ntfs_log_leave("\n"); + return (!ok); +rl_err_out: + /* + * need not restore old sizes, only compressed_size + * can have changed. It has been set according to + * the current runlist while updating the mapping pairs, + * and must be kept consistent with the runlists. + */ +err_out: + eo = errno; + if (ctx) + ntfs_attr_put_search_ctx(ctx); + /* Update mapping pairs if needed. */ + ntfs_attr_update_mapping_pairs(na, 0 /*update_from*/); + errno = eo; +errno_set: + ok = FALSE; + goto out; +} + +/** + * ntfs_attr_mst_pread - multi sector transfer protected ntfs attribute read + * @na: multi sector transfer protected ntfs attribute to read from + * @pos: byte position in the attribute to begin reading from + * @bk_cnt: number of mst protected blocks to read + * @bk_size: size of each mst protected block in bytes + * @dst: output data buffer + * + * This function will read @bk_cnt blocks of size @bk_size bytes each starting + * at offset @pos from the ntfs attribute @na into the data buffer @b. + * + * On success, the multi sector transfer fixups are applied and the number of + * read blocks is returned. If this number is lower than @bk_cnt this means + * that the read has either reached end of attribute or that an error was + * encountered during the read so that the read is partial. 0 means end of + * attribute or nothing to read (also return 0 when @bk_cnt or @bk_size are 0). + * + * On error and nothing has been read, return -1 with errno set appropriately + * to the return code of ntfs_attr_pread() or to EINVAL in case of invalid + * arguments. + * + * NOTE: If an incomplete multi sector transfer is detected the magic is + * changed to BAAD but no error is returned, i.e. it is possible that any of + * the returned blocks have multi sector transfer errors. This should be + * detected by the caller by checking each block with is_baad_recordp(&block). + * The reasoning is that we want to fixup as many blocks as possible and we + * want to return even bad ones to the caller so, e.g. in case of ntfsck, the + * errors can be repaired. + */ +s64 ntfs_attr_mst_pread(ntfs_attr *na, const s64 pos, const s64 bk_cnt, + const u32 bk_size, void *dst) +{ + s64 br; + u8 *end; + + ntfs_log_trace("Entering for inode 0x%llx, attr type 0x%x, pos 0x%llx.\n", + (unsigned long long)na->ni->mft_no, na->type, + (long long)pos); + if (bk_cnt < 0 || bk_size % NTFS_BLOCK_SIZE) { + errno = EINVAL; + ntfs_log_perror("%s", __FUNCTION__); + return -1; + } + br = ntfs_attr_pread(na, pos, bk_cnt * bk_size, dst); + if (br <= 0) + return br; + br /= bk_size; + for (end = (u8*)dst + br * bk_size; (u8*)dst < end; dst = (u8*)dst + + bk_size) + ntfs_mst_post_read_fixup((NTFS_RECORD*)dst, bk_size); + /* Finally, return the number of blocks read. */ + return br; +} + +/** + * ntfs_attr_mst_pwrite - multi sector transfer protected ntfs attribute write + * @na: multi sector transfer protected ntfs attribute to write to + * @pos: position in the attribute to write to + * @bk_cnt: number of mst protected blocks to write + * @bk_size: size of each mst protected block in bytes + * @src: data buffer to write to disk + * + * This function will write @bk_cnt blocks of size @bk_size bytes each from + * data buffer @b to multi sector transfer (mst) protected ntfs attribute @na + * at position @pos. + * + * On success, return the number of successfully written blocks. If this number + * is lower than @bk_cnt this means that an error was encountered during the + * write so that the write is partial. 0 means nothing was written (also + * return 0 when @bk_cnt or @bk_size are 0). + * + * On error and nothing has been written, return -1 with errno set + * appropriately to the return code of ntfs_attr_pwrite(), or to EINVAL in case + * of invalid arguments. + * + * NOTE: We mst protect the data, write it, then mst deprotect it using a quick + * deprotect algorithm (no checking). This saves us from making a copy before + * the write and at the same time causes the usn to be incremented in the + * buffer. This conceptually fits in better with the idea that cached data is + * always deprotected and protection is performed when the data is actually + * going to hit the disk and the cache is immediately deprotected again + * simulating an mst read on the written data. This way cache coherency is + * achieved. + */ +s64 ntfs_attr_mst_pwrite(ntfs_attr *na, const s64 pos, s64 bk_cnt, + const u32 bk_size, void *src) +{ + s64 written, i; + + ntfs_log_trace("Entering for inode 0x%llx, attr type 0x%x, pos 0x%llx.\n", + (unsigned long long)na->ni->mft_no, na->type, + (long long)pos); + if (bk_cnt < 0 || bk_size % NTFS_BLOCK_SIZE) { + errno = EINVAL; + return -1; + } + if (!bk_cnt) + return 0; + /* Prepare data for writing. */ + for (i = 0; i < bk_cnt; ++i) { + int err; + + err = ntfs_mst_pre_write_fixup((NTFS_RECORD*) + ((u8*)src + i * bk_size), bk_size); + if (err < 0) { + /* Abort write at this position. */ + ntfs_log_perror("%s #1", __FUNCTION__); + if (!i) + return err; + bk_cnt = i; + break; + } + } + /* Write the prepared data. */ + written = ntfs_attr_pwrite(na, pos, bk_cnt * bk_size, src); + if (written <= 0) { + ntfs_log_perror("%s: written=%lld", __FUNCTION__, + (long long)written); + } + /* Quickly deprotect the data again. */ + for (i = 0; i < bk_cnt; ++i) + ntfs_mst_post_write_fixup((NTFS_RECORD*)((u8*)src + i * + bk_size)); + if (written <= 0) + return written; + /* Finally, return the number of complete blocks written. */ + return written / bk_size; +} + +/** + * ntfs_attr_find - find (next) attribute in mft record + * @type: attribute type to find + * @name: attribute name to find (optional, i.e. NULL means don't care) + * @name_len: attribute name length (only needed if @name present) + * @ic: IGNORE_CASE or CASE_SENSITIVE (ignored if @name not present) + * @val: attribute value to find (optional, resident attributes only) + * @val_len: attribute value length + * @ctx: search context with mft record and attribute to search from + * + * You shouldn't need to call this function directly. Use lookup_attr() instead. + * + * ntfs_attr_find() takes a search context @ctx as parameter and searches the + * mft record specified by @ctx->mrec, beginning at @ctx->attr, for an + * attribute of @type, optionally @name and @val. If found, ntfs_attr_find() + * returns 0 and @ctx->attr will point to the found attribute. + * + * If not found, ntfs_attr_find() returns -1, with errno set to ENOENT and + * @ctx->attr will point to the attribute before which the attribute being + * searched for would need to be inserted if such an action were to be desired. + * + * On actual error, ntfs_attr_find() returns -1 with errno set to the error + * code but not to ENOENT. In this case @ctx->attr is undefined and in + * particular do not rely on it not changing. + * + * If @ctx->is_first is TRUE, the search begins with @ctx->attr itself. If it + * is FALSE, the search begins after @ctx->attr. + * + * If @type is AT_UNUSED, return the first found attribute, i.e. one can + * enumerate all attributes by setting @type to AT_UNUSED and then calling + * ntfs_attr_find() repeatedly until it returns -1 with errno set to ENOENT to + * indicate that there are no more entries. During the enumeration, each + * successful call of ntfs_attr_find() will return the next attribute in the + * mft record @ctx->mrec. + * + * If @type is AT_END, seek to the end and return -1 with errno set to ENOENT. + * AT_END is not a valid attribute, its length is zero for example, thus it is + * safer to return error instead of success in this case. This also allows us + * to interoperate cleanly with ntfs_external_attr_find(). + * + * If @name is AT_UNNAMED search for an unnamed attribute. If @name is present + * but not AT_UNNAMED search for a named attribute matching @name. Otherwise, + * match both named and unnamed attributes. + * + * If @ic is IGNORE_CASE, the @name comparison is not case sensitive and + * @ctx->ntfs_ino must be set to the ntfs inode to which the mft record + * @ctx->mrec belongs. This is so we can get at the ntfs volume and hence at + * the upcase table. If @ic is CASE_SENSITIVE, the comparison is case + * sensitive. When @name is present, @name_len is the @name length in Unicode + * characters. + * + * If @name is not present (NULL), we assume that the unnamed attribute is + * being searched for. + * + * Finally, the resident attribute value @val is looked for, if present. + * If @val is not present (NULL), @val_len is ignored. + * + * ntfs_attr_find() only searches the specified mft record and it ignores the + * presence of an attribute list attribute (unless it is the one being searched + * for, obviously). If you need to take attribute lists into consideration, use + * ntfs_attr_lookup() instead (see below). This also means that you cannot use + * ntfs_attr_find() to search for extent records of non-resident attributes, as + * extents with lowest_vcn != 0 are usually described by the attribute list + * attribute only. - Note that it is possible that the first extent is only in + * the attribute list while the last extent is in the base mft record, so don't + * rely on being able to find the first extent in the base mft record. + * + * Warning: Never use @val when looking for attribute types which can be + * non-resident as this most likely will result in a crash! + */ +static int ntfs_attr_find(const ATTR_TYPES type, const ntfschar *name, + const u32 name_len, const IGNORE_CASE_BOOL ic, + const u8 *val, const u32 val_len, ntfs_attr_search_ctx *ctx) +{ + ATTR_RECORD *a; + ntfs_volume *vol; + ntfschar *upcase; + u32 upcase_len; + + ntfs_log_trace("attribute type 0x%x.\n", type); + + if (ctx->ntfs_ino) { + vol = ctx->ntfs_ino->vol; + upcase = vol->upcase; + upcase_len = vol->upcase_len; + } else { + if (name && name != AT_UNNAMED) { + errno = EINVAL; + ntfs_log_perror("%s", __FUNCTION__); + return -1; + } + vol = NULL; + upcase = NULL; + upcase_len = 0; + } + /* + * Iterate over attributes in mft record starting at @ctx->attr, or the + * attribute following that, if @ctx->is_first is TRUE. + */ + if (ctx->is_first) { + a = ctx->attr; + ctx->is_first = FALSE; + } else + a = (ATTR_RECORD*)((char*)ctx->attr + + le32_to_cpu(ctx->attr->length)); + for (;; a = (ATTR_RECORD*)((char*)a + le32_to_cpu(a->length))) { + if (p2n(a) < p2n(ctx->mrec) || (char*)a > (char*)ctx->mrec + + le32_to_cpu(ctx->mrec->bytes_allocated)) + break; + ctx->attr = a; + if (((type != AT_UNUSED) && (le32_to_cpu(a->type) > + le32_to_cpu(type))) || + (a->type == AT_END)) { + errno = ENOENT; + return -1; + } + if (!a->length) + break; + /* If this is an enumeration return this attribute. */ + if (type == AT_UNUSED) + return 0; + if (a->type != type) + continue; + /* + * If @name is AT_UNNAMED we want an unnamed attribute. + * If @name is present, compare the two names. + * Otherwise, match any attribute. + */ + if (name == AT_UNNAMED) { + /* The search failed if the found attribute is named. */ + if (a->name_length) { + errno = ENOENT; + return -1; + } + } else { + register int rc; + if (name && ((rc = ntfs_names_full_collate(name, + name_len, (ntfschar*)((char*)a + + le16_to_cpu(a->name_offset)), + a->name_length, ic, + upcase, upcase_len)))) { + /* + * If @name collates before a->name, + * there is no matching attribute. + */ + if (rc < 0) { + errno = ENOENT; + return -1; + } + /* If the strings are not equal, continue search. */ + continue; + } + } + /* + * The names match or @name not present and attribute is + * unnamed. If no @val specified, we have found the attribute + * and are done. + */ + if (!val) + return 0; + /* @val is present; compare values. */ + else { + register int rc; + + rc = memcmp(val, (char*)a +le16_to_cpu(a->value_offset), + min(val_len, + le32_to_cpu(a->value_length))); + /* + * If @val collates before the current attribute's + * value, there is no matching attribute. + */ + if (!rc) { + register u32 avl; + avl = le32_to_cpu(a->value_length); + if (val_len == avl) + return 0; + if (val_len < avl) { + errno = ENOENT; + return -1; + } + } else if (rc < 0) { + errno = ENOENT; + return -1; + } + } + } + errno = EIO; + ntfs_log_perror("%s: Corrupt inode (%lld)", __FUNCTION__, + ctx->ntfs_ino ? (long long)ctx->ntfs_ino->mft_no : -1); + return -1; +} + +void ntfs_attr_name_free(char **name) +{ + if (*name) { + free(*name); + *name = NULL; + } +} + +char *ntfs_attr_name_get(const ntfschar *uname, const int uname_len) +{ + char *name = NULL; + int name_len; + + name_len = ntfs_ucstombs(uname, uname_len, &name, 0); + if (name_len < 0) { + ntfs_log_perror("ntfs_ucstombs"); + return NULL; + + } else if (name_len > 0) + return name; + + ntfs_attr_name_free(&name); + return NULL; +} + +/** + * ntfs_external_attr_find - find an attribute in the attribute list of an inode + * @type: attribute type to find + * @name: attribute name to find (optional, i.e. NULL means don't care) + * @name_len: attribute name length (only needed if @name present) + * @ic: IGNORE_CASE or CASE_SENSITIVE (ignored if @name not present) + * @lowest_vcn: lowest vcn to find (optional, non-resident attributes only) + * @val: attribute value to find (optional, resident attributes only) + * @val_len: attribute value length + * @ctx: search context with mft record and attribute to search from + * + * You shouldn't need to call this function directly. Use ntfs_attr_lookup() + * instead. + * + * Find an attribute by searching the attribute list for the corresponding + * attribute list entry. Having found the entry, map the mft record for read + * if the attribute is in a different mft record/inode, find the attribute in + * there and return it. + * + * If @type is AT_UNUSED, return the first found attribute, i.e. one can + * enumerate all attributes by setting @type to AT_UNUSED and then calling + * ntfs_external_attr_find() repeatedly until it returns -1 with errno set to + * ENOENT to indicate that there are no more entries. During the enumeration, + * each successful call of ntfs_external_attr_find() will return the next + * attribute described by the attribute list of the base mft record described + * by the search context @ctx. + * + * If @type is AT_END, seek to the end of the base mft record ignoring the + * attribute list completely and return -1 with errno set to ENOENT. AT_END is + * not a valid attribute, its length is zero for example, thus it is safer to + * return error instead of success in this case. + * + * If @name is AT_UNNAMED search for an unnamed attribute. If @name is present + * but not AT_UNNAMED search for a named attribute matching @name. Otherwise, + * match both named and unnamed attributes. + * + * On first search @ctx->ntfs_ino must be the inode of the base mft record and + * @ctx must have been obtained from a call to ntfs_attr_get_search_ctx(). + * On subsequent calls, @ctx->ntfs_ino can be any extent inode, too + * (@ctx->base_ntfs_ino is then the base inode). + * + * After finishing with the attribute/mft record you need to call + * ntfs_attr_put_search_ctx() to cleanup the search context (unmapping any + * mapped extent inodes, etc). + * + * Return 0 if the search was successful and -1 if not, with errno set to the + * error code. + * + * On success, @ctx->attr is the found attribute, it is in mft record + * @ctx->mrec, and @ctx->al_entry is the attribute list entry for this + * attribute with @ctx->base_* being the base mft record to which @ctx->attr + * belongs. + * + * On error ENOENT, i.e. attribute not found, @ctx->attr is set to the + * attribute which collates just after the attribute being searched for in the + * base ntfs inode, i.e. if one wants to add the attribute to the mft record + * this is the correct place to insert it into, and if there is not enough + * space, the attribute should be placed in an extent mft record. + * @ctx->al_entry points to the position within @ctx->base_ntfs_ino->attr_list + * at which the new attribute's attribute list entry should be inserted. The + * other @ctx fields, base_ntfs_ino, base_mrec, and base_attr are set to NULL. + * The only exception to this is when @type is AT_END, in which case + * @ctx->al_entry is set to NULL also (see above). + * + * The following error codes are defined: + * ENOENT Attribute not found, not an error as such. + * EINVAL Invalid arguments. + * EIO I/O error or corrupt data structures found. + * ENOMEM Not enough memory to allocate necessary buffers. + */ +static int ntfs_external_attr_find(ATTR_TYPES type, const ntfschar *name, + const u32 name_len, const IGNORE_CASE_BOOL ic, + const VCN lowest_vcn, const u8 *val, const u32 val_len, + ntfs_attr_search_ctx *ctx) +{ + ntfs_inode *base_ni, *ni; + ntfs_volume *vol; + ATTR_LIST_ENTRY *al_entry, *next_al_entry; + u8 *al_start, *al_end; + ATTR_RECORD *a; + ntfschar *al_name; + u32 al_name_len; + BOOL is_first_search = FALSE; + + ni = ctx->ntfs_ino; + base_ni = ctx->base_ntfs_ino; + ntfs_log_trace("Entering for inode %lld, attribute type 0x%x.\n", + (unsigned long long)ni->mft_no, type); + if (!base_ni) { + /* First call happens with the base mft record. */ + base_ni = ctx->base_ntfs_ino = ctx->ntfs_ino; + ctx->base_mrec = ctx->mrec; + } + if (ni == base_ni) + ctx->base_attr = ctx->attr; + if (type == AT_END) + goto not_found; + vol = base_ni->vol; + al_start = base_ni->attr_list; + al_end = al_start + base_ni->attr_list_size; + if (!ctx->al_entry) { + ctx->al_entry = (ATTR_LIST_ENTRY*)al_start; + is_first_search = TRUE; + } + /* + * Iterate over entries in attribute list starting at @ctx->al_entry, + * or the entry following that, if @ctx->is_first is TRUE. + */ + if (ctx->is_first) { + al_entry = ctx->al_entry; + ctx->is_first = FALSE; + /* + * If an enumeration and the first attribute is higher than + * the attribute list itself, need to return the attribute list + * attribute. + */ + if ((type == AT_UNUSED) && is_first_search && + le32_to_cpu(al_entry->type) > + le32_to_cpu(AT_ATTRIBUTE_LIST)) + goto find_attr_list_attr; + } else { + al_entry = (ATTR_LIST_ENTRY*)((char*)ctx->al_entry + + le16_to_cpu(ctx->al_entry->length)); + /* + * If this is an enumeration and the attribute list attribute + * is the next one in the enumeration sequence, just return the + * attribute list attribute from the base mft record as it is + * not listed in the attribute list itself. + */ + if ((type == AT_UNUSED) && le32_to_cpu(ctx->al_entry->type) < + le32_to_cpu(AT_ATTRIBUTE_LIST) && + le32_to_cpu(al_entry->type) > + le32_to_cpu(AT_ATTRIBUTE_LIST)) { + int rc; +find_attr_list_attr: + + /* Check for bogus calls. */ + if (name || name_len || val || val_len || lowest_vcn) { + errno = EINVAL; + ntfs_log_perror("%s", __FUNCTION__); + return -1; + } + + /* We want the base record. */ + ctx->ntfs_ino = base_ni; + ctx->mrec = ctx->base_mrec; + ctx->is_first = TRUE; + /* Sanity checks are performed elsewhere. */ + ctx->attr = (ATTR_RECORD*)((u8*)ctx->mrec + + le16_to_cpu(ctx->mrec->attrs_offset)); + + /* Find the attribute list attribute. */ + rc = ntfs_attr_find(AT_ATTRIBUTE_LIST, NULL, 0, + IGNORE_CASE, NULL, 0, ctx); + + /* + * Setup the search context so the correct + * attribute is returned next time round. + */ + ctx->al_entry = al_entry; + ctx->is_first = TRUE; + + /* Got it. Done. */ + if (!rc) + return 0; + + /* Error! If other than not found return it. */ + if (errno != ENOENT) + return rc; + + /* Not found?!? Absurd! */ + errno = EIO; + ntfs_log_error("Attribute list wasn't found"); + return -1; + } + } + for (;; al_entry = next_al_entry) { + /* Out of bounds check. */ + if ((u8*)al_entry < base_ni->attr_list || + (u8*)al_entry > al_end) + break; /* Inode is corrupt. */ + ctx->al_entry = al_entry; + /* Catch the end of the attribute list. */ + if ((u8*)al_entry == al_end) + goto not_found; + if (!al_entry->length) + break; + if ((u8*)al_entry + 6 > al_end || (u8*)al_entry + + le16_to_cpu(al_entry->length) > al_end) + break; + next_al_entry = (ATTR_LIST_ENTRY*)((u8*)al_entry + + le16_to_cpu(al_entry->length)); + if (type != AT_UNUSED) { + if (le32_to_cpu(al_entry->type) > le32_to_cpu(type)) + goto not_found; + if (type != al_entry->type) + continue; + } + al_name_len = al_entry->name_length; + al_name = (ntfschar*)((u8*)al_entry + al_entry->name_offset); + /* + * If !@type we want the attribute represented by this + * attribute list entry. + */ + if (type == AT_UNUSED) + goto is_enumeration; + /* + * If @name is AT_UNNAMED we want an unnamed attribute. + * If @name is present, compare the two names. + * Otherwise, match any attribute. + */ + if (name == AT_UNNAMED) { + if (al_name_len) + goto not_found; + } else { + int rc; + + if (name && ((rc = ntfs_names_full_collate(name, + name_len, al_name, al_name_len, ic, + vol->upcase, vol->upcase_len)))) { + + /* + * If @name collates before al_name, + * there is no matching attribute. + */ + if (rc < 0) + goto not_found; + /* If the strings are not equal, continue search. */ + continue; + } + } + /* + * The names match or @name not present and attribute is + * unnamed. Now check @lowest_vcn. Continue search if the + * next attribute list entry still fits @lowest_vcn. Otherwise + * we have reached the right one or the search has failed. + */ + if (lowest_vcn && (u8*)next_al_entry >= al_start && + (u8*)next_al_entry + 6 < al_end && + (u8*)next_al_entry + le16_to_cpu( + next_al_entry->length) <= al_end && + sle64_to_cpu(next_al_entry->lowest_vcn) <= + lowest_vcn && + next_al_entry->type == al_entry->type && + next_al_entry->name_length == al_name_len && + ntfs_names_are_equal((ntfschar*)((char*) + next_al_entry + + next_al_entry->name_offset), + next_al_entry->name_length, + al_name, al_name_len, CASE_SENSITIVE, + vol->upcase, vol->upcase_len)) + continue; +is_enumeration: + if (MREF_LE(al_entry->mft_reference) == ni->mft_no) { + if (MSEQNO_LE(al_entry->mft_reference) != + le16_to_cpu( + ni->mrec->sequence_number)) { + ntfs_log_error("Found stale mft reference in " + "attribute list!\n"); + break; + } + } else { /* Mft references do not match. */ + /* Do we want the base record back? */ + if (MREF_LE(al_entry->mft_reference) == + base_ni->mft_no) { + ni = ctx->ntfs_ino = base_ni; + ctx->mrec = ctx->base_mrec; + } else { + /* We want an extent record. */ + ni = ntfs_extent_inode_open(base_ni, + al_entry->mft_reference); + if (!ni) + break; + ctx->ntfs_ino = ni; + ctx->mrec = ni->mrec; + } + } + a = ctx->attr = (ATTR_RECORD*)((char*)ctx->mrec + + le16_to_cpu(ctx->mrec->attrs_offset)); + /* + * ctx->ntfs_ino, ctx->mrec, and ctx->attr now point to the + * mft record containing the attribute represented by the + * current al_entry. + * + * We could call into ntfs_attr_find() to find the right + * attribute in this mft record but this would be less + * efficient and not quite accurate as ntfs_attr_find() ignores + * the attribute instance numbers for example which become + * important when one plays with attribute lists. Also, because + * a proper match has been found in the attribute list entry + * above, the comparison can now be optimized. So it is worth + * re-implementing a simplified ntfs_attr_find() here. + * + * Use a manual loop so we can still use break and continue + * with the same meanings as above. + */ +do_next_attr_loop: + if ((char*)a < (char*)ctx->mrec || (char*)a > (char*)ctx->mrec + + le32_to_cpu(ctx->mrec->bytes_allocated)) + break; + if (a->type == AT_END) + continue; + if (!a->length) + break; + if (al_entry->instance != a->instance) + goto do_next_attr; + /* + * If the type and/or the name are/is mismatched between the + * attribute list entry and the attribute record, there is + * corruption so we break and return error EIO. + */ + if (al_entry->type != a->type) + break; + if (!ntfs_names_are_equal((ntfschar*)((char*)a + + le16_to_cpu(a->name_offset)), + a->name_length, al_name, + al_name_len, CASE_SENSITIVE, + vol->upcase, vol->upcase_len)) + break; + ctx->attr = a; + /* + * If no @val specified or @val specified and it matches, we + * have found it! Also, if !@type, it is an enumeration, so we + * want the current attribute. + */ + if ((type == AT_UNUSED) || !val || (!a->non_resident && + le32_to_cpu(a->value_length) == val_len && + !memcmp((char*)a + le16_to_cpu(a->value_offset), + val, val_len))) { + return 0; + } +do_next_attr: + /* Proceed to the next attribute in the current mft record. */ + a = (ATTR_RECORD*)((char*)a + le32_to_cpu(a->length)); + goto do_next_attr_loop; + } + if (ni != base_ni) { + ctx->ntfs_ino = base_ni; + ctx->mrec = ctx->base_mrec; + ctx->attr = ctx->base_attr; + } + errno = EIO; + ntfs_log_perror("Inode is corrupt (%lld)", (long long)base_ni->mft_no); + return -1; +not_found: + /* + * If we were looking for AT_END or we were enumerating and reached the + * end, we reset the search context @ctx and use ntfs_attr_find() to + * seek to the end of the base mft record. + */ + if (type == AT_UNUSED || type == AT_END) { + ntfs_attr_reinit_search_ctx(ctx); + return ntfs_attr_find(AT_END, name, name_len, ic, val, val_len, + ctx); + } + /* + * The attribute wasn't found. Before we return, we want to ensure + * @ctx->mrec and @ctx->attr indicate the position at which the + * attribute should be inserted in the base mft record. Since we also + * want to preserve @ctx->al_entry we cannot reinitialize the search + * context using ntfs_attr_reinit_search_ctx() as this would set + * @ctx->al_entry to NULL. Thus we do the necessary bits manually (see + * ntfs_attr_init_search_ctx() below). Note, we _only_ preserve + * @ctx->al_entry as the remaining fields (base_*) are identical to + * their non base_ counterparts and we cannot set @ctx->base_attr + * correctly yet as we do not know what @ctx->attr will be set to by + * the call to ntfs_attr_find() below. + */ + ctx->mrec = ctx->base_mrec; + ctx->attr = (ATTR_RECORD*)((u8*)ctx->mrec + + le16_to_cpu(ctx->mrec->attrs_offset)); + ctx->is_first = TRUE; + ctx->ntfs_ino = ctx->base_ntfs_ino; + ctx->base_ntfs_ino = NULL; + ctx->base_mrec = NULL; + ctx->base_attr = NULL; + /* + * In case there are multiple matches in the base mft record, need to + * keep enumerating until we get an attribute not found response (or + * another error), otherwise we would keep returning the same attribute + * over and over again and all programs using us for enumeration would + * lock up in a tight loop. + */ + { + int ret; + + do { + ret = ntfs_attr_find(type, name, name_len, ic, val, + val_len, ctx); + } while (!ret); + return ret; + } +} + +/** + * ntfs_attr_lookup - find an attribute in an ntfs inode + * @type: attribute type to find + * @name: attribute name to find (optional, i.e. NULL means don't care) + * @name_len: attribute name length (only needed if @name present) + * @ic: IGNORE_CASE or CASE_SENSITIVE (ignored if @name not present) + * @lowest_vcn: lowest vcn to find (optional, non-resident attributes only) + * @val: attribute value to find (optional, resident attributes only) + * @val_len: attribute value length + * @ctx: search context with mft record and attribute to search from + * + * Find an attribute in an ntfs inode. On first search @ctx->ntfs_ino must + * be the base mft record and @ctx must have been obtained from a call to + * ntfs_attr_get_search_ctx(). + * + * This function transparently handles attribute lists and @ctx is used to + * continue searches where they were left off at. + * + * If @type is AT_UNUSED, return the first found attribute, i.e. one can + * enumerate all attributes by setting @type to AT_UNUSED and then calling + * ntfs_attr_lookup() repeatedly until it returns -1 with errno set to ENOENT + * to indicate that there are no more entries. During the enumeration, each + * successful call of ntfs_attr_lookup() will return the next attribute, with + * the current attribute being described by the search context @ctx. + * + * If @type is AT_END, seek to the end of the base mft record ignoring the + * attribute list completely and return -1 with errno set to ENOENT. AT_END is + * not a valid attribute, its length is zero for example, thus it is safer to + * return error instead of success in this case. It should never be needed to + * do this, but we implement the functionality because it allows for simpler + * code inside ntfs_external_attr_find(). + * + * If @name is AT_UNNAMED search for an unnamed attribute. If @name is present + * but not AT_UNNAMED search for a named attribute matching @name. Otherwise, + * match both named and unnamed attributes. + * + * After finishing with the attribute/mft record you need to call + * ntfs_attr_put_search_ctx() to cleanup the search context (unmapping any + * mapped extent inodes, etc). + * + * Return 0 if the search was successful and -1 if not, with errno set to the + * error code. + * + * On success, @ctx->attr is the found attribute, it is in mft record + * @ctx->mrec, and @ctx->al_entry is the attribute list entry for this + * attribute with @ctx->base_* being the base mft record to which @ctx->attr + * belongs. If no attribute list attribute is present @ctx->al_entry and + * @ctx->base_* are NULL. + * + * On error ENOENT, i.e. attribute not found, @ctx->attr is set to the + * attribute which collates just after the attribute being searched for in the + * base ntfs inode, i.e. if one wants to add the attribute to the mft record + * this is the correct place to insert it into, and if there is not enough + * space, the attribute should be placed in an extent mft record. + * @ctx->al_entry points to the position within @ctx->base_ntfs_ino->attr_list + * at which the new attribute's attribute list entry should be inserted. The + * other @ctx fields, base_ntfs_ino, base_mrec, and base_attr are set to NULL. + * The only exception to this is when @type is AT_END, in which case + * @ctx->al_entry is set to NULL also (see above). + * + * + * The following error codes are defined: + * ENOENT Attribute not found, not an error as such. + * EINVAL Invalid arguments. + * EIO I/O error or corrupt data structures found. + * ENOMEM Not enough memory to allocate necessary buffers. + */ +int ntfs_attr_lookup(const ATTR_TYPES type, const ntfschar *name, + const u32 name_len, const IGNORE_CASE_BOOL ic, + const VCN lowest_vcn, const u8 *val, const u32 val_len, + ntfs_attr_search_ctx *ctx) +{ + ntfs_volume *vol; + ntfs_inode *base_ni; + int ret = -1; + + ntfs_log_enter("Entering for attribute type 0x%x\n", type); + + if (!ctx || !ctx->mrec || !ctx->attr || (name && name != AT_UNNAMED && + (!ctx->ntfs_ino || !(vol = ctx->ntfs_ino->vol) || + !vol->upcase || !vol->upcase_len))) { + errno = EINVAL; + ntfs_log_perror("%s", __FUNCTION__); + goto out; + } + + if (ctx->base_ntfs_ino) + base_ni = ctx->base_ntfs_ino; + else + base_ni = ctx->ntfs_ino; + if (!base_ni || !NInoAttrList(base_ni) || type == AT_ATTRIBUTE_LIST) + ret = ntfs_attr_find(type, name, name_len, ic, val, val_len, ctx); + else + ret = ntfs_external_attr_find(type, name, name_len, ic, + lowest_vcn, val, val_len, ctx); +out: + ntfs_log_leave("\n"); + return ret; +} + +/** + * ntfs_attr_position - find given or next attribute type in an ntfs inode + * @type: attribute type to start lookup + * @ctx: search context with mft record and attribute to search from + * + * Find an attribute type in an ntfs inode or the next attribute which is not + * the AT_END attribute. Please see more details at ntfs_attr_lookup. + * + * Return 0 if the search was successful and -1 if not, with errno set to the + * error code. + * + * The following error codes are defined: + * EINVAL Invalid arguments. + * EIO I/O error or corrupt data structures found. + * ENOMEM Not enough memory to allocate necessary buffers. + * ENOSPC No attribute was found after 'type', only AT_END. + */ +int ntfs_attr_position(const ATTR_TYPES type, ntfs_attr_search_ctx *ctx) +{ + if (ntfs_attr_lookup(type, NULL, 0, CASE_SENSITIVE, 0, NULL, 0, ctx)) { + if (errno != ENOENT) + return -1; + if (ctx->attr->type == AT_END) { + errno = ENOSPC; + return -1; + } + } + return 0; +} + +/** + * ntfs_attr_init_search_ctx - initialize an attribute search context + * @ctx: attribute search context to initialize + * @ni: ntfs inode with which to initialize the search context + * @mrec: mft record with which to initialize the search context + * + * Initialize the attribute search context @ctx with @ni and @mrec. + */ +static void ntfs_attr_init_search_ctx(ntfs_attr_search_ctx *ctx, + ntfs_inode *ni, MFT_RECORD *mrec) +{ + if (!mrec) + mrec = ni->mrec; + ctx->mrec = mrec; + /* Sanity checks are performed elsewhere. */ + ctx->attr = (ATTR_RECORD*)((u8*)mrec + le16_to_cpu(mrec->attrs_offset)); + ctx->is_first = TRUE; + ctx->ntfs_ino = ni; + ctx->al_entry = NULL; + ctx->base_ntfs_ino = NULL; + ctx->base_mrec = NULL; + ctx->base_attr = NULL; +} + +/** + * ntfs_attr_reinit_search_ctx - reinitialize an attribute search context + * @ctx: attribute search context to reinitialize + * + * Reinitialize the attribute search context @ctx. + * + * This is used when a search for a new attribute is being started to reset + * the search context to the beginning. + */ +void ntfs_attr_reinit_search_ctx(ntfs_attr_search_ctx *ctx) +{ + if (!ctx->base_ntfs_ino) { + /* No attribute list. */ + ctx->is_first = TRUE; + /* Sanity checks are performed elsewhere. */ + ctx->attr = (ATTR_RECORD*)((u8*)ctx->mrec + + le16_to_cpu(ctx->mrec->attrs_offset)); + /* + * This needs resetting due to ntfs_external_attr_find() which + * can leave it set despite having zeroed ctx->base_ntfs_ino. + */ + ctx->al_entry = NULL; + return; + } /* Attribute list. */ + ntfs_attr_init_search_ctx(ctx, ctx->base_ntfs_ino, ctx->base_mrec); + return; +} + +/** + * ntfs_attr_get_search_ctx - allocate/initialize a new attribute search context + * @ni: ntfs inode with which to initialize the search context + * @mrec: mft record with which to initialize the search context + * + * Allocate a new attribute search context, initialize it with @ni and @mrec, + * and return it. Return NULL on error with errno set. + * + * @mrec can be NULL, in which case the mft record is taken from @ni. + * + * Note: For low level utilities which know what they are doing we allow @ni to + * be NULL and @mrec to be set. Do NOT do this unless you understand the + * implications!!! For example it is no longer safe to call ntfs_attr_lookup(). + */ +ntfs_attr_search_ctx *ntfs_attr_get_search_ctx(ntfs_inode *ni, MFT_RECORD *mrec) +{ + ntfs_attr_search_ctx *ctx; + + if (!ni && !mrec) { + errno = EINVAL; + ntfs_log_perror("NULL arguments"); + return NULL; + } + ctx = ntfs_malloc(sizeof(ntfs_attr_search_ctx)); + if (ctx) + ntfs_attr_init_search_ctx(ctx, ni, mrec); + return ctx; +} + +/** + * ntfs_attr_put_search_ctx - release an attribute search context + * @ctx: attribute search context to free + * + * Release the attribute search context @ctx. + */ +void ntfs_attr_put_search_ctx(ntfs_attr_search_ctx *ctx) +{ + // NOTE: save errno if it could change and function stays void! + free(ctx); +} + +/** + * ntfs_attr_find_in_attrdef - find an attribute in the $AttrDef system file + * @vol: ntfs volume to which the attribute belongs + * @type: attribute type which to find + * + * Search for the attribute definition record corresponding to the attribute + * @type in the $AttrDef system file. + * + * Return the attribute type definition record if found and NULL if not found + * or an error occurred. On error the error code is stored in errno. The + * following error codes are defined: + * ENOENT - The attribute @type is not specified in $AttrDef. + * EINVAL - Invalid parameters (e.g. @vol is not valid). + */ +ATTR_DEF *ntfs_attr_find_in_attrdef(const ntfs_volume *vol, + const ATTR_TYPES type) +{ + ATTR_DEF *ad; + + if (!vol || !vol->attrdef || !type) { + errno = EINVAL; + ntfs_log_perror("%s: type=%d", __FUNCTION__, type); + return NULL; + } + for (ad = vol->attrdef; (u8*)ad - (u8*)vol->attrdef < + vol->attrdef_len && ad->type; ++ad) { + /* We haven't found it yet, carry on searching. */ + if (le32_to_cpu(ad->type) < le32_to_cpu(type)) + continue; + /* We found the attribute; return it. */ + if (ad->type == type) + return ad; + /* We have gone too far already. No point in continuing. */ + break; + } + errno = ENOENT; + ntfs_log_perror("%s: type=%d", __FUNCTION__, type); + return NULL; +} + +/** + * ntfs_attr_size_bounds_check - check a size of an attribute type for validity + * @vol: ntfs volume to which the attribute belongs + * @type: attribute type which to check + * @size: size which to check + * + * Check whether the @size in bytes is valid for an attribute of @type on the + * ntfs volume @vol. This information is obtained from $AttrDef system file. + * + * Return 0 if valid and -1 if not valid or an error occurred. On error the + * error code is stored in errno. The following error codes are defined: + * ERANGE - @size is not valid for the attribute @type. + * ENOENT - The attribute @type is not specified in $AttrDef. + * EINVAL - Invalid parameters (e.g. @size is < 0 or @vol is not valid). + */ +int ntfs_attr_size_bounds_check(const ntfs_volume *vol, const ATTR_TYPES type, + const s64 size) +{ + ATTR_DEF *ad; + s64 min_size, max_size; + + if (size < 0) { + errno = EINVAL; + ntfs_log_perror("%s: size=%lld", __FUNCTION__, + (long long)size); + return -1; + } + + /* + * $ATTRIBUTE_LIST shouldn't be greater than 0x40000, otherwise + * Windows would crash. This is not listed in the AttrDef. + */ + if (type == AT_ATTRIBUTE_LIST && size > 0x40000) { + errno = ERANGE; + ntfs_log_perror("Too large attrlist (%lld)", (long long)size); + return -1; + } + + ad = ntfs_attr_find_in_attrdef(vol, type); + if (!ad) + return -1; + + min_size = sle64_to_cpu(ad->min_size); + max_size = sle64_to_cpu(ad->max_size); + + if ((min_size && (size < min_size)) || + ((max_size > 0) && (size > max_size))) { + errno = ERANGE; + ntfs_log_perror("Attr type %d size check failed (min,size,max=" + "%lld,%lld,%lld)", type, (long long)min_size, + (long long)size, (long long)max_size); + return -1; + } + return 0; +} + +/** + * ntfs_attr_can_be_non_resident - check if an attribute can be non-resident + * @vol: ntfs volume to which the attribute belongs + * @type: attribute type to check + * @name: attribute name to check + * @name_len: attribute name length + * + * Check whether the attribute of @type and @name with name length @name_len on + * the ntfs volume @vol is allowed to be non-resident. This information is + * obtained from $AttrDef system file and is augmented by rules imposed by + * Microsoft (e.g. see http://support.microsoft.com/kb/974729/). + * + * Return 0 if the attribute is allowed to be non-resident and -1 if not or an + * error occurred. On error the error code is stored in errno. The following + * error codes are defined: + * EPERM - The attribute is not allowed to be non-resident. + * ENOENT - The attribute @type is not specified in $AttrDef. + * EINVAL - Invalid parameters (e.g. @vol is not valid). + */ +static int ntfs_attr_can_be_non_resident(const ntfs_volume *vol, const ATTR_TYPES type, + const ntfschar *name, int name_len) +{ + ATTR_DEF *ad; + BOOL allowed; + + /* + * Microsoft has decreed that $LOGGED_UTILITY_STREAM attributes with a + * name of $TXF_DATA must be resident despite the entry for + * $LOGGED_UTILITY_STREAM in $AttrDef allowing them to be non-resident. + * Failure to obey this on the root directory mft record of a volume + * causes Windows Vista and later to see the volume as a RAW volume and + * thus cannot mount it at all. + */ + if ((type == AT_LOGGED_UTILITY_STREAM) + && name + && ntfs_names_are_equal(TXF_DATA, 9, name, name_len, + CASE_SENSITIVE, vol->upcase, vol->upcase_len)) + allowed = FALSE; + else { + /* Find the attribute definition record in $AttrDef. */ + ad = ntfs_attr_find_in_attrdef(vol, type); + if (!ad) + return -1; + /* Check the flags and return the result. */ + allowed = !(ad->flags & ATTR_DEF_RESIDENT); + } + if (!allowed) { + errno = EPERM; + ntfs_log_trace("Attribute can't be non-resident\n"); + return -1; + } + return 0; +} + +/** + * ntfs_attr_can_be_resident - check if an attribute can be resident + * @vol: ntfs volume to which the attribute belongs + * @type: attribute type which to check + * + * Check whether the attribute of @type on the ntfs volume @vol is allowed to + * be resident. This information is derived from our ntfs knowledge and may + * not be completely accurate, especially when user defined attributes are + * present. Basically we allow everything to be resident except for index + * allocation and extended attribute attributes. + * + * Return 0 if the attribute is allowed to be resident and -1 if not or an + * error occurred. On error the error code is stored in errno. The following + * error codes are defined: + * EPERM - The attribute is not allowed to be resident. + * EINVAL - Invalid parameters (e.g. @vol is not valid). + * + * Warning: In the system file $MFT the attribute $Bitmap must be non-resident + * otherwise windows will not boot (blue screen of death)! We cannot + * check for this here as we don't know which inode's $Bitmap is being + * asked about so the caller needs to special case this. + */ +int ntfs_attr_can_be_resident(const ntfs_volume *vol, const ATTR_TYPES type) +{ + if (!vol || !vol->attrdef || !type) { + errno = EINVAL; + return -1; + } + if (type != AT_INDEX_ALLOCATION) + return 0; + + ntfs_log_trace("Attribute can't be resident\n"); + errno = EPERM; + return -1; +} + +/** + * ntfs_make_room_for_attr - make room for an attribute inside an mft record + * @m: mft record + * @pos: position at which to make space + * @size: byte size to make available at this position + * + * @pos points to the attribute in front of which we want to make space. + * + * Return 0 on success or -1 on error. On error the error code is stored in + * errno. Possible error codes are: + * ENOSPC - There is not enough space available to complete operation. The + * caller has to make space before calling this. + * EINVAL - Input parameters were faulty. + */ +int ntfs_make_room_for_attr(MFT_RECORD *m, u8 *pos, u32 size) +{ + u32 biu; + + ntfs_log_trace("Entering for pos 0x%d, size %u.\n", + (int)(pos - (u8*)m), (unsigned) size); + + /* Make size 8-byte alignment. */ + size = (size + 7) & ~7; + + /* Rigorous consistency checks. */ + if (!m || !pos || pos < (u8*)m) { + errno = EINVAL; + ntfs_log_perror("%s: pos=%p m=%p", __FUNCTION__, pos, m); + return -1; + } + /* The -8 is for the attribute terminator. */ + if (pos - (u8*)m > (int)le32_to_cpu(m->bytes_in_use) - 8) { + errno = EINVAL; + return -1; + } + /* Nothing to do. */ + if (!size) + return 0; + + biu = le32_to_cpu(m->bytes_in_use); + /* Do we have enough space? */ + if (biu + size > le32_to_cpu(m->bytes_allocated) || + pos + size > (u8*)m + le32_to_cpu(m->bytes_allocated)) { + errno = ENOSPC; + ntfs_log_trace("No enough space in the MFT record\n"); + return -1; + } + /* Move everything after pos to pos + size. */ + memmove(pos + size, pos, biu - (pos - (u8*)m)); + /* Update mft record. */ + m->bytes_in_use = cpu_to_le32(biu + size); + return 0; +} + +/** + * ntfs_resident_attr_record_add - add resident attribute to inode + * @ni: opened ntfs inode to which MFT record add attribute + * @type: type of the new attribute + * @name: name of the new attribute + * @name_len: name length of the new attribute + * @val: value of the new attribute + * @size: size of new attribute (length of @val, if @val != NULL) + * @flags: flags of the new attribute + * + * Return offset to attribute from the beginning of the mft record on success + * and -1 on error. On error the error code is stored in errno. + * Possible error codes are: + * EINVAL - Invalid arguments passed to function. + * EEXIST - Attribute of such type and with same name already exists. + * EIO - I/O error occurred or damaged filesystem. + */ +int ntfs_resident_attr_record_add(ntfs_inode *ni, ATTR_TYPES type, + ntfschar *name, u8 name_len, u8 *val, u32 size, + ATTR_FLAGS data_flags) +{ + ntfs_attr_search_ctx *ctx; + u32 length; + ATTR_RECORD *a; + MFT_RECORD *m; + int err, offset; + ntfs_inode *base_ni; + + ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x, flags 0x%x.\n", + (long long) ni->mft_no, (unsigned) type, (unsigned) data_flags); + + if (!ni || (!name && name_len)) { + errno = EINVAL; + return -1; + } + + if (ntfs_attr_can_be_resident(ni->vol, type)) { + if (errno == EPERM) + ntfs_log_trace("Attribute can't be resident.\n"); + else + ntfs_log_trace("ntfs_attr_can_be_resident failed.\n"); + return -1; + } + + /* Locate place where record should be. */ + ctx = ntfs_attr_get_search_ctx(ni, NULL); + if (!ctx) + return -1; + /* + * Use ntfs_attr_find instead of ntfs_attr_lookup to find place for + * attribute in @ni->mrec, not any extent inode in case if @ni is base + * file record. + */ + if (!ntfs_attr_find(type, name, name_len, CASE_SENSITIVE, val, size, + ctx)) { + err = EEXIST; + ntfs_log_trace("Attribute already present.\n"); + goto put_err_out; + } + if (errno != ENOENT) { + err = EIO; + goto put_err_out; + } + a = ctx->attr; + m = ctx->mrec; + + /* Make room for attribute. */ + length = offsetof(ATTR_RECORD, resident_end) + + ((name_len * sizeof(ntfschar) + 7) & ~7) + + ((size + 7) & ~7); + if (ntfs_make_room_for_attr(ctx->mrec, (u8*) ctx->attr, length)) { + err = errno; + ntfs_log_trace("Failed to make room for attribute.\n"); + goto put_err_out; + } + + /* Setup record fields. */ + offset = ((u8*)a - (u8*)m); + a->type = type; + a->length = cpu_to_le32(length); + a->non_resident = 0; + a->name_length = name_len; + a->name_offset = (name_len + ? cpu_to_le16(offsetof(ATTR_RECORD, resident_end)) + : const_cpu_to_le16(0)); + a->flags = data_flags; + a->instance = m->next_attr_instance; + a->value_length = cpu_to_le32(size); + a->value_offset = cpu_to_le16(length - ((size + 7) & ~7)); + if (val) + memcpy((u8*)a + le16_to_cpu(a->value_offset), val, size); + else + memset((u8*)a + le16_to_cpu(a->value_offset), 0, size); + if (type == AT_FILE_NAME) + a->resident_flags = RESIDENT_ATTR_IS_INDEXED; + else + a->resident_flags = 0; + if (name_len) + memcpy((u8*)a + le16_to_cpu(a->name_offset), + name, sizeof(ntfschar) * name_len); + m->next_attr_instance = + cpu_to_le16((le16_to_cpu(m->next_attr_instance) + 1) & 0xffff); + if (ni->nr_extents == -1) + base_ni = ni->base_ni; + else + base_ni = ni; + if (type != AT_ATTRIBUTE_LIST && NInoAttrList(base_ni)) { + if (ntfs_attrlist_entry_add(ni, a)) { + err = errno; + ntfs_attr_record_resize(m, a, 0); + ntfs_log_trace("Failed add attribute entry to " + "ATTRIBUTE_LIST.\n"); + goto put_err_out; + } + } + if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY + ? type == AT_INDEX_ROOT && name == NTFS_INDEX_I30 + : type == AT_DATA && name == AT_UNNAMED) { + ni->data_size = size; + ni->allocated_size = (size + 7) & ~7; + set_nino_flag(ni,KnownSize); + } + ntfs_inode_mark_dirty(ni); + ntfs_attr_put_search_ctx(ctx); + return offset; +put_err_out: + ntfs_attr_put_search_ctx(ctx); + errno = err; + return -1; +} + +/** + * ntfs_non_resident_attr_record_add - add extent of non-resident attribute + * @ni: opened ntfs inode to which MFT record add attribute + * @type: type of the new attribute extent + * @name: name of the new attribute extent + * @name_len: name length of the new attribute extent + * @lowest_vcn: lowest vcn of the new attribute extent + * @dataruns_size: dataruns size of the new attribute extent + * @flags: flags of the new attribute extent + * + * Return offset to attribute from the beginning of the mft record on success + * and -1 on error. On error the error code is stored in errno. + * Possible error codes are: + * EINVAL - Invalid arguments passed to function. + * EEXIST - Attribute of such type, with same lowest vcn and with same + * name already exists. + * EIO - I/O error occurred or damaged filesystem. + */ +int ntfs_non_resident_attr_record_add(ntfs_inode *ni, ATTR_TYPES type, + ntfschar *name, u8 name_len, VCN lowest_vcn, int dataruns_size, + ATTR_FLAGS flags) +{ + ntfs_attr_search_ctx *ctx; + u32 length; + ATTR_RECORD *a; + MFT_RECORD *m; + ntfs_inode *base_ni; + int err, offset; + + ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x, lowest_vcn %lld, " + "dataruns_size %d, flags 0x%x.\n", + (long long) ni->mft_no, (unsigned) type, + (long long) lowest_vcn, dataruns_size, (unsigned) flags); + + if (!ni || dataruns_size <= 0 || (!name && name_len)) { + errno = EINVAL; + return -1; + } + + if (ntfs_attr_can_be_non_resident(ni->vol, type, name, name_len)) { + if (errno == EPERM) + ntfs_log_perror("Attribute can't be non resident"); + else + ntfs_log_perror("ntfs_attr_can_be_non_resident failed"); + return -1; + } + + /* Locate place where record should be. */ + ctx = ntfs_attr_get_search_ctx(ni, NULL); + if (!ctx) + return -1; + /* + * Use ntfs_attr_find instead of ntfs_attr_lookup to find place for + * attribute in @ni->mrec, not any extent inode in case if @ni is base + * file record. + */ + if (!ntfs_attr_find(type, name, name_len, CASE_SENSITIVE, NULL, 0, + ctx)) { + err = EEXIST; + ntfs_log_perror("Attribute 0x%x already present", type); + goto put_err_out; + } + if (errno != ENOENT) { + ntfs_log_perror("ntfs_attr_find failed"); + err = EIO; + goto put_err_out; + } + a = ctx->attr; + m = ctx->mrec; + + /* Make room for attribute. */ + dataruns_size = (dataruns_size + 7) & ~7; + length = offsetof(ATTR_RECORD, compressed_size) + ((sizeof(ntfschar) * + name_len + 7) & ~7) + dataruns_size + + ((flags & (ATTR_IS_COMPRESSED | ATTR_IS_SPARSE)) ? + sizeof(a->compressed_size) : 0); + if (ntfs_make_room_for_attr(ctx->mrec, (u8*) ctx->attr, length)) { + err = errno; + ntfs_log_perror("Failed to make room for attribute"); + goto put_err_out; + } + + /* Setup record fields. */ + a->type = type; + a->length = cpu_to_le32(length); + a->non_resident = 1; + a->name_length = name_len; + a->name_offset = cpu_to_le16(offsetof(ATTR_RECORD, compressed_size) + + ((flags & (ATTR_IS_COMPRESSED | ATTR_IS_SPARSE)) ? + sizeof(a->compressed_size) : 0)); + a->flags = flags; + a->instance = m->next_attr_instance; + a->lowest_vcn = cpu_to_sle64(lowest_vcn); + a->mapping_pairs_offset = cpu_to_le16(length - dataruns_size); + a->compression_unit = (flags & ATTR_IS_COMPRESSED) + ? STANDARD_COMPRESSION_UNIT : 0; + /* If @lowest_vcn == 0, than setup empty attribute. */ + if (!lowest_vcn) { + a->highest_vcn = cpu_to_sle64(-1); + a->allocated_size = 0; + a->data_size = 0; + a->initialized_size = 0; + /* Set empty mapping pairs. */ + *((u8*)a + le16_to_cpu(a->mapping_pairs_offset)) = 0; + } + if (name_len) + memcpy((u8*)a + le16_to_cpu(a->name_offset), + name, sizeof(ntfschar) * name_len); + m->next_attr_instance = + cpu_to_le16((le16_to_cpu(m->next_attr_instance) + 1) & 0xffff); + if (ni->nr_extents == -1) + base_ni = ni->base_ni; + else + base_ni = ni; + if (type != AT_ATTRIBUTE_LIST && NInoAttrList(base_ni)) { + if (ntfs_attrlist_entry_add(ni, a)) { + err = errno; + ntfs_log_perror("Failed add attr entry to attrlist"); + ntfs_attr_record_resize(m, a, 0); + goto put_err_out; + } + } + ntfs_inode_mark_dirty(ni); + /* + * Locate offset from start of the MFT record where new attribute is + * placed. We need relookup it, because record maybe moved during + * update of attribute list. + */ + ntfs_attr_reinit_search_ctx(ctx); + if (ntfs_attr_lookup(type, name, name_len, CASE_SENSITIVE, + lowest_vcn, NULL, 0, ctx)) { + ntfs_log_perror("%s: attribute lookup failed", __FUNCTION__); + ntfs_attr_put_search_ctx(ctx); + return -1; + + } + offset = (u8*)ctx->attr - (u8*)ctx->mrec; + ntfs_attr_put_search_ctx(ctx); + return offset; +put_err_out: + ntfs_attr_put_search_ctx(ctx); + errno = err; + return -1; +} + +/** + * ntfs_attr_record_rm - remove attribute extent + * @ctx: search context describing the attribute which should be removed + * + * If this function succeed, user should reinit search context if he/she wants + * use it anymore. + * + * Return 0 on success and -1 on error. On error the error code is stored in + * errno. Possible error codes are: + * EINVAL - Invalid arguments passed to function. + * EIO - I/O error occurred or damaged filesystem. + */ +int ntfs_attr_record_rm(ntfs_attr_search_ctx *ctx) +{ + ntfs_inode *base_ni, *ni; + ATTR_TYPES type; + + if (!ctx || !ctx->ntfs_ino || !ctx->mrec || !ctx->attr) { + errno = EINVAL; + return -1; + } + + ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x.\n", + (long long) ctx->ntfs_ino->mft_no, + (unsigned) le32_to_cpu(ctx->attr->type)); + type = ctx->attr->type; + ni = ctx->ntfs_ino; + if (ctx->base_ntfs_ino) + base_ni = ctx->base_ntfs_ino; + else + base_ni = ctx->ntfs_ino; + + /* Remove attribute itself. */ + if (ntfs_attr_record_resize(ctx->mrec, ctx->attr, 0)) { + ntfs_log_trace("Couldn't remove attribute record. Bug or damaged MFT " + "record.\n"); + if (NInoAttrList(base_ni) && type != AT_ATTRIBUTE_LIST) + if (ntfs_attrlist_entry_add(ni, ctx->attr)) + ntfs_log_trace("Rollback failed. Leaving inconstant " + "metadata.\n"); + errno = EIO; + return -1; + } + ntfs_inode_mark_dirty(ni); + + /* + * Remove record from $ATTRIBUTE_LIST if present and we don't want + * delete $ATTRIBUTE_LIST itself. + */ + if (NInoAttrList(base_ni) && type != AT_ATTRIBUTE_LIST) { + if (ntfs_attrlist_entry_rm(ctx)) { + ntfs_log_trace("Couldn't delete record from " + "$ATTRIBUTE_LIST.\n"); + return -1; + } + } + + /* Post $ATTRIBUTE_LIST delete setup. */ + if (type == AT_ATTRIBUTE_LIST) { + if (NInoAttrList(base_ni) && base_ni->attr_list) + free(base_ni->attr_list); + base_ni->attr_list = NULL; + NInoClearAttrList(base_ni); + NInoAttrListClearDirty(base_ni); + } + + /* Free MFT record, if it doesn't contain attributes. */ + if (le32_to_cpu(ctx->mrec->bytes_in_use) - + le16_to_cpu(ctx->mrec->attrs_offset) == 8) { + if (ntfs_mft_record_free(ni->vol, ni)) { + // FIXME: We need rollback here. + ntfs_log_trace("Couldn't free MFT record.\n"); + errno = EIO; + return -1; + } + /* Remove done if we freed base inode. */ + if (ni == base_ni) + return 0; + } + + if (type == AT_ATTRIBUTE_LIST || !NInoAttrList(base_ni)) + return 0; + + /* Remove attribute list if we don't need it any more. */ + if (!ntfs_attrlist_need(base_ni)) { + ntfs_attr_reinit_search_ctx(ctx); + if (ntfs_attr_lookup(AT_ATTRIBUTE_LIST, NULL, 0, CASE_SENSITIVE, + 0, NULL, 0, ctx)) { + /* + * FIXME: Should we succeed here? Definitely something + * goes wrong because NInoAttrList(base_ni) returned + * that we have got attribute list. + */ + ntfs_log_trace("Couldn't find attribute list. Succeed " + "anyway.\n"); + return 0; + } + /* Deallocate clusters. */ + if (ctx->attr->non_resident) { + runlist *al_rl; + + al_rl = ntfs_mapping_pairs_decompress(base_ni->vol, + ctx->attr, NULL); + if (!al_rl) { + ntfs_log_trace("Couldn't decompress attribute list " + "runlist. Succeed anyway.\n"); + return 0; + } + if (ntfs_cluster_free_from_rl(base_ni->vol, al_rl)) { + ntfs_log_trace("Leaking clusters! Run chkdsk. " + "Couldn't free clusters from " + "attribute list runlist.\n"); + } + free(al_rl); + } + /* Remove attribute record itself. */ + if (ntfs_attr_record_rm(ctx)) { + /* + * FIXME: Should we succeed here? BTW, chkdsk doesn't + * complain if it find MFT record with attribute list, + * but without extents. + */ + ntfs_log_trace("Couldn't remove attribute list. Succeed " + "anyway.\n"); + return 0; + } + } + return 0; +} + +/** + * ntfs_attr_add - add attribute to inode + * @ni: opened ntfs inode to which add attribute + * @type: type of the new attribute + * @name: name in unicode of the new attribute + * @name_len: name length in unicode characters of the new attribute + * @val: value of new attribute + * @size: size of the new attribute / length of @val (if specified) + * + * @val should always be specified for always resident attributes (eg. FILE_NAME + * attribute), for attributes that can become non-resident @val can be NULL + * (eg. DATA attribute). @size can be specified even if @val is NULL, in this + * case data size will be equal to @size and initialized size will be equal + * to 0. + * + * If inode haven't got enough space to add attribute, add attribute to one of + * it extents, if no extents present or no one of them have enough space, than + * allocate new extent and add attribute to it. + * + * If on one of this steps attribute list is needed but not present, than it is + * added transparently to caller. So, this function should not be called with + * @type == AT_ATTRIBUTE_LIST, if you really need to add attribute list call + * ntfs_inode_add_attrlist instead. + * + * On success return 0. On error return -1 with errno set to the error code. + */ +int ntfs_attr_add(ntfs_inode *ni, ATTR_TYPES type, + ntfschar *name, u8 name_len, u8 *val, s64 size) +{ + u32 attr_rec_size; + int err, i, offset; + BOOL is_resident; + BOOL can_be_non_resident = FALSE; + ntfs_inode *attr_ni; + ntfs_attr *na; + ATTR_FLAGS data_flags; + + if (!ni || size < 0 || type == AT_ATTRIBUTE_LIST) { + errno = EINVAL; + ntfs_log_perror("%s: ni=%p size=%lld", __FUNCTION__, ni, + (long long)size); + return -1; + } + + ntfs_log_trace("Entering for inode %lld, attr %x, size %lld.\n", + (long long)ni->mft_no, type, (long long)size); + + if (ni->nr_extents == -1) + ni = ni->base_ni; + + /* Check the attribute type and the size. */ + if (ntfs_attr_size_bounds_check(ni->vol, type, size)) { + if (errno == ENOENT) + errno = EIO; + return -1; + } + + /* Sanity checks for always resident attributes. */ + if (ntfs_attr_can_be_non_resident(ni->vol, type, name, name_len)) { + if (errno != EPERM) { + err = errno; + ntfs_log_perror("ntfs_attr_can_be_non_resident failed"); + goto err_out; + } + /* @val is mandatory. */ + if (!val) { + errno = EINVAL; + ntfs_log_perror("val is mandatory for always resident " + "attributes"); + return -1; + } + if (size > ni->vol->mft_record_size) { + errno = ERANGE; + ntfs_log_perror("Attribute is too big"); + return -1; + } + } else + can_be_non_resident = TRUE; + + /* + * Determine resident or not will be new attribute. We add 8 to size in + * non resident case for mapping pairs. + */ + if (!ntfs_attr_can_be_resident(ni->vol, type)) { + is_resident = TRUE; + } else { + if (errno != EPERM) { + err = errno; + ntfs_log_perror("ntfs_attr_can_be_resident failed"); + goto err_out; + } + is_resident = FALSE; + } + /* Calculate attribute record size. */ + if (is_resident) + attr_rec_size = offsetof(ATTR_RECORD, resident_end) + + ((name_len * sizeof(ntfschar) + 7) & ~7) + + ((size + 7) & ~7); + else + attr_rec_size = offsetof(ATTR_RECORD, non_resident_end) + + ((name_len * sizeof(ntfschar) + 7) & ~7) + 8; + + /* + * If we have enough free space for the new attribute in the base MFT + * record, then add attribute to it. + */ + if (le32_to_cpu(ni->mrec->bytes_allocated) - + le32_to_cpu(ni->mrec->bytes_in_use) >= attr_rec_size) { + attr_ni = ni; + goto add_attr_record; + } + + /* Try to add to extent inodes. */ + if (ntfs_inode_attach_all_extents(ni)) { + err = errno; + ntfs_log_perror("Failed to attach all extents to inode"); + goto err_out; + } + for (i = 0; i < ni->nr_extents; i++) { + attr_ni = ni->extent_nis[i]; + if (le32_to_cpu(attr_ni->mrec->bytes_allocated) - + le32_to_cpu(attr_ni->mrec->bytes_in_use) >= + attr_rec_size) + goto add_attr_record; + } + + /* There is no extent that contain enough space for new attribute. */ + if (!NInoAttrList(ni)) { + /* Add attribute list not present, add it and retry. */ + if (ntfs_inode_add_attrlist(ni)) { + err = errno; + ntfs_log_perror("Failed to add attribute list"); + goto err_out; + } + return ntfs_attr_add(ni, type, name, name_len, val, size); + } + /* Allocate new extent. */ + attr_ni = ntfs_mft_record_alloc(ni->vol, ni); + if (!attr_ni) { + err = errno; + ntfs_log_perror("Failed to allocate extent record"); + goto err_out; + } + +add_attr_record: + if ((ni->flags & FILE_ATTR_COMPRESSED) + && (ni->vol->cluster_size <= MAX_COMPRESSION_CLUSTER_SIZE) + && ((type == AT_DATA) + || ((type == AT_INDEX_ROOT) && (name == NTFS_INDEX_I30)))) + data_flags = ATTR_IS_COMPRESSED; + else + data_flags = const_cpu_to_le16(0); + if (is_resident) { + /* Add resident attribute. */ + offset = ntfs_resident_attr_record_add(attr_ni, type, name, + name_len, val, size, data_flags); + if (offset < 0) { + if (errno == ENOSPC && can_be_non_resident) + goto add_non_resident; + err = errno; + ntfs_log_perror("Failed to add resident attribute"); + goto free_err_out; + } + return 0; + } + +add_non_resident: + /* Add non resident attribute. */ + offset = ntfs_non_resident_attr_record_add(attr_ni, type, name, + name_len, 0, 8, data_flags); + if (offset < 0) { + err = errno; + ntfs_log_perror("Failed to add non resident attribute"); + goto free_err_out; + } + + /* If @size == 0, we are done. */ + if (!size) + return 0; + + /* Open new attribute and resize it. */ + na = ntfs_attr_open(ni, type, name, name_len); + if (!na) { + err = errno; + ntfs_log_perror("Failed to open just added attribute"); + goto rm_attr_err_out; + } + /* Resize and set attribute value. */ + if (ntfs_attr_truncate(na, size) || + (val && (ntfs_attr_pwrite(na, 0, size, val) != size))) { + err = errno; + ntfs_log_perror("Failed to initialize just added attribute"); + if (ntfs_attr_rm(na)) + ntfs_log_perror("Failed to remove just added attribute"); + ntfs_attr_close(na); + goto err_out; + } + ntfs_attr_close(na); + return 0; + +rm_attr_err_out: + /* Remove just added attribute. */ + if (ntfs_attr_record_resize(attr_ni->mrec, + (ATTR_RECORD*)((u8*)attr_ni->mrec + offset), 0)) + ntfs_log_perror("Failed to remove just added attribute #2"); +free_err_out: + /* Free MFT record, if it doesn't contain attributes. */ + if (le32_to_cpu(attr_ni->mrec->bytes_in_use) - + le16_to_cpu(attr_ni->mrec->attrs_offset) == 8) + if (ntfs_mft_record_free(attr_ni->vol, attr_ni)) + ntfs_log_perror("Failed to free MFT record"); +err_out: + errno = err; + return -1; +} + +/* + * Change an attribute flag + */ + +int ntfs_attr_set_flags(ntfs_inode *ni, ATTR_TYPES type, + ntfschar *name, u8 name_len, ATTR_FLAGS flags, ATTR_FLAGS mask) +{ + ntfs_attr_search_ctx *ctx; + int res; + + res = -1; + /* Search for designated attribute */ + ctx = ntfs_attr_get_search_ctx(ni, NULL); + if (ctx) { + if (!ntfs_attr_lookup(type, name, name_len, + CASE_SENSITIVE, 0, NULL, 0, ctx)) { + /* do the requested change (all small endian le16) */ + ctx->attr->flags = (ctx->attr->flags & ~mask) + | (flags & mask); + NInoSetDirty(ni); + res = 0; + } + ntfs_attr_put_search_ctx(ctx); + } + return (res); +} + + +/** + * ntfs_attr_rm - remove attribute from ntfs inode + * @na: opened ntfs attribute to delete + * + * Remove attribute and all it's extents from ntfs inode. If attribute was non + * resident also free all clusters allocated by attribute. + * + * Return 0 on success or -1 on error with errno set to the error code. + */ +int ntfs_attr_rm(ntfs_attr *na) +{ + ntfs_attr_search_ctx *ctx; + int ret = 0; + + if (!na) { + ntfs_log_trace("Invalid arguments passed.\n"); + errno = EINVAL; + return -1; + } + + ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x.\n", + (long long) na->ni->mft_no, na->type); + + /* Free cluster allocation. */ + if (NAttrNonResident(na)) { + if (ntfs_attr_map_whole_runlist(na)) + return -1; + if (ntfs_cluster_free(na->ni->vol, na, 0, -1) < 0) { + ntfs_log_trace("Failed to free cluster allocation. Leaving " + "inconstant metadata.\n"); + ret = -1; + } + } + + /* Search for attribute extents and remove them all. */ + ctx = ntfs_attr_get_search_ctx(na->ni, NULL); + if (!ctx) + return -1; + while (!ntfs_attr_lookup(na->type, na->name, na->name_len, + CASE_SENSITIVE, 0, NULL, 0, ctx)) { + if (ntfs_attr_record_rm(ctx)) { + ntfs_log_trace("Failed to remove attribute extent. Leaving " + "inconstant metadata.\n"); + ret = -1; + } + ntfs_attr_reinit_search_ctx(ctx); + } + ntfs_attr_put_search_ctx(ctx); + if (errno != ENOENT) { + ntfs_log_trace("Attribute lookup failed. Probably leaving inconstant " + "metadata.\n"); + ret = -1; + } + + return ret; +} + +/** + * ntfs_attr_record_resize - resize an attribute record + * @m: mft record containing attribute record + * @a: attribute record to resize + * @new_size: new size in bytes to which to resize the attribute record @a + * + * Resize the attribute record @a, i.e. the resident part of the attribute, in + * the mft record @m to @new_size bytes. + * + * Return 0 on success and -1 on error with errno set to the error code. + * The following error codes are defined: + * ENOSPC - Not enough space in the mft record @m to perform the resize. + * Note that on error no modifications have been performed whatsoever. + * + * Warning: If you make a record smaller without having copied all the data you + * are interested in the data may be overwritten! + */ +int ntfs_attr_record_resize(MFT_RECORD *m, ATTR_RECORD *a, u32 new_size) +{ + u32 old_size, alloc_size, attr_size; + + old_size = le32_to_cpu(m->bytes_in_use); + alloc_size = le32_to_cpu(m->bytes_allocated); + attr_size = le32_to_cpu(a->length); + + ntfs_log_trace("Sizes: old=%u alloc=%u attr=%u new=%u\n", + (unsigned)old_size, (unsigned)alloc_size, + (unsigned)attr_size, (unsigned)new_size); + + /* Align to 8 bytes, just in case the caller hasn't. */ + new_size = (new_size + 7) & ~7; + + /* If the actual attribute length has changed, move things around. */ + if (new_size != attr_size) { + + u32 new_muse = old_size - attr_size + new_size; + + /* Not enough space in this mft record. */ + if (new_muse > alloc_size) { + errno = ENOSPC; + ntfs_log_trace("Not enough space in the MFT record " + "(%u > %u)\n", new_muse, alloc_size); + return -1; + } + + if (a->type == AT_INDEX_ROOT && new_size > attr_size && + new_muse + 120 > alloc_size && old_size + 120 <= alloc_size) { + errno = ENOSPC; + ntfs_log_trace("Too big INDEX_ROOT (%u > %u)\n", + new_muse, alloc_size); + return STATUS_RESIDENT_ATTRIBUTE_FILLED_MFT; + } + + /* Move attributes following @a to their new location. */ + memmove((u8 *)a + new_size, (u8 *)a + attr_size, + old_size - ((u8 *)a - (u8 *)m) - attr_size); + + /* Adjust @m to reflect the change in used space. */ + m->bytes_in_use = cpu_to_le32(new_muse); + + /* Adjust @a to reflect the new size. */ + if (new_size >= offsetof(ATTR_REC, length) + sizeof(a->length)) + a->length = cpu_to_le32(new_size); + } + return 0; +} + +/** + * ntfs_resident_attr_value_resize - resize the value of a resident attribute + * @m: mft record containing attribute record + * @a: attribute record whose value to resize + * @new_size: new size in bytes to which to resize the attribute value of @a + * + * Resize the value of the attribute @a in the mft record @m to @new_size bytes. + * If the value is made bigger, the newly "allocated" space is cleared. + * + * Return 0 on success and -1 on error with errno set to the error code. + * The following error codes are defined: + * ENOSPC - Not enough space in the mft record @m to perform the resize. + * Note that on error no modifications have been performed whatsoever. + */ +int ntfs_resident_attr_value_resize(MFT_RECORD *m, ATTR_RECORD *a, + const u32 new_size) +{ + int ret; + + ntfs_log_trace("Entering for new size %u.\n", (unsigned)new_size); + + /* Resize the resident part of the attribute record. */ + if ((ret = ntfs_attr_record_resize(m, a, (le16_to_cpu(a->value_offset) + + new_size + 7) & ~7)) < 0) + return ret; + /* + * If we made the attribute value bigger, clear the area between the + * old size and @new_size. + */ + if (new_size > le32_to_cpu(a->value_length)) + memset((u8*)a + le16_to_cpu(a->value_offset) + + le32_to_cpu(a->value_length), 0, new_size - + le32_to_cpu(a->value_length)); + /* Finally update the length of the attribute value. */ + a->value_length = cpu_to_le32(new_size); + return 0; +} + +/** + * ntfs_attr_record_move_to - move attribute record to target inode + * @ctx: attribute search context describing the attribute record + * @ni: opened ntfs inode to which move attribute record + * + * If this function succeed, user should reinit search context if he/she wants + * use it anymore. + * + * Return 0 on success and -1 on error with errno set to the error code. + */ +int ntfs_attr_record_move_to(ntfs_attr_search_ctx *ctx, ntfs_inode *ni) +{ + ntfs_attr_search_ctx *nctx; + ATTR_RECORD *a; + int err; + + if (!ctx || !ctx->attr || !ctx->ntfs_ino || !ni) { + ntfs_log_trace("Invalid arguments passed.\n"); + errno = EINVAL; + return -1; + } + + ntfs_log_trace("Entering for ctx->attr->type 0x%x, ctx->ntfs_ino->mft_no " + "0x%llx, ni->mft_no 0x%llx.\n", + (unsigned) le32_to_cpu(ctx->attr->type), + (long long) ctx->ntfs_ino->mft_no, + (long long) ni->mft_no); + + if (ctx->ntfs_ino == ni) + return 0; + + if (!ctx->al_entry) { + ntfs_log_trace("Inode should contain attribute list to use this " + "function.\n"); + errno = EINVAL; + return -1; + } + + /* Find place in MFT record where attribute will be moved. */ + a = ctx->attr; + nctx = ntfs_attr_get_search_ctx(ni, NULL); + if (!nctx) + return -1; + + /* + * Use ntfs_attr_find instead of ntfs_attr_lookup to find place for + * attribute in @ni->mrec, not any extent inode in case if @ni is base + * file record. + */ + if (!ntfs_attr_find(a->type, (ntfschar*)((u8*)a + le16_to_cpu( + a->name_offset)), a->name_length, CASE_SENSITIVE, NULL, + 0, nctx)) { + ntfs_log_trace("Attribute of such type, with same name already " + "present in this MFT record.\n"); + err = EEXIST; + goto put_err_out; + } + if (errno != ENOENT) { + err = errno; + ntfs_log_debug("Attribute lookup failed.\n"); + goto put_err_out; + } + + /* Make space and move attribute. */ + if (ntfs_make_room_for_attr(ni->mrec, (u8*) nctx->attr, + le32_to_cpu(a->length))) { + err = errno; + ntfs_log_trace("Couldn't make space for attribute.\n"); + goto put_err_out; + } + memcpy(nctx->attr, a, le32_to_cpu(a->length)); + nctx->attr->instance = nctx->mrec->next_attr_instance; + nctx->mrec->next_attr_instance = cpu_to_le16( + (le16_to_cpu(nctx->mrec->next_attr_instance) + 1) & 0xffff); + ntfs_attr_record_resize(ctx->mrec, a, 0); + ntfs_inode_mark_dirty(ctx->ntfs_ino); + ntfs_inode_mark_dirty(ni); + + /* Update attribute list. */ + ctx->al_entry->mft_reference = + MK_LE_MREF(ni->mft_no, le16_to_cpu(ni->mrec->sequence_number)); + ctx->al_entry->instance = nctx->attr->instance; + ntfs_attrlist_mark_dirty(ni); + + ntfs_attr_put_search_ctx(nctx); + return 0; +put_err_out: + ntfs_attr_put_search_ctx(nctx); + errno = err; + return -1; +} + +/** + * ntfs_attr_record_move_away - move away attribute record from it's mft record + * @ctx: attribute search context describing the attribute record + * @extra: minimum amount of free space in the new holder of record + * + * New attribute record holder must have free @extra bytes after moving + * attribute record to it. + * + * If this function succeed, user should reinit search context if he/she wants + * use it anymore. + * + * Return 0 on success and -1 on error with errno set to the error code. + */ +int ntfs_attr_record_move_away(ntfs_attr_search_ctx *ctx, int extra) +{ + ntfs_inode *base_ni, *ni; + MFT_RECORD *m; + int i; + + if (!ctx || !ctx->attr || !ctx->ntfs_ino || extra < 0) { + errno = EINVAL; + ntfs_log_perror("%s: ctx=%p ctx->attr=%p extra=%d", __FUNCTION__, + ctx, ctx ? ctx->attr : NULL, extra); + return -1; + } + + ntfs_log_trace("Entering for attr 0x%x, inode %llu\n", + (unsigned) le32_to_cpu(ctx->attr->type), + (unsigned long long)ctx->ntfs_ino->mft_no); + + if (ctx->ntfs_ino->nr_extents == -1) + base_ni = ctx->base_ntfs_ino; + else + base_ni = ctx->ntfs_ino; + + if (!NInoAttrList(base_ni)) { + errno = EINVAL; + ntfs_log_perror("Inode %llu has no attrlist", + (unsigned long long)base_ni->mft_no); + return -1; + } + + if (ntfs_inode_attach_all_extents(ctx->ntfs_ino)) { + ntfs_log_perror("Couldn't attach extents, inode=%llu", + (unsigned long long)base_ni->mft_no); + return -1; + } + + /* Walk through all extents and try to move attribute to them. */ + for (i = 0; i < base_ni->nr_extents; i++) { + ni = base_ni->extent_nis[i]; + m = ni->mrec; + + if (ctx->ntfs_ino->mft_no == ni->mft_no) + continue; + + if (le32_to_cpu(m->bytes_allocated) - + le32_to_cpu(m->bytes_in_use) < + le32_to_cpu(ctx->attr->length) + extra) + continue; + + /* + * ntfs_attr_record_move_to can fail if extent with other lowest + * VCN already present in inode we trying move record to. So, + * do not return error. + */ + if (!ntfs_attr_record_move_to(ctx, ni)) + return 0; + } + + /* + * Failed to move attribute to one of the current extents, so allocate + * new extent and move attribute to it. + */ + ni = ntfs_mft_record_alloc(base_ni->vol, base_ni); + if (!ni) { + ntfs_log_perror("Couldn't allocate MFT record"); + return -1; + } + if (ntfs_attr_record_move_to(ctx, ni)) { + ntfs_log_perror("Couldn't move attribute to MFT record"); + return -1; + } + return 0; +} + +/** + * ntfs_attr_make_non_resident - convert a resident to a non-resident attribute + * @na: open ntfs attribute to make non-resident + * @ctx: ntfs search context describing the attribute + * + * Convert a resident ntfs attribute to a non-resident one. + * + * Return 0 on success and -1 on error with errno set to the error code. The + * following error codes are defined: + * EPERM - The attribute is not allowed to be non-resident. + * TODO: others... + * + * NOTE to self: No changes in the attribute list are required to move from + * a resident to a non-resident attribute. + * + * Warning: We do not set the inode dirty and we do not write out anything! + * We expect the caller to do this as this is a fairly low level + * function and it is likely there will be further changes made. + */ +int ntfs_attr_make_non_resident(ntfs_attr *na, + ntfs_attr_search_ctx *ctx) +{ + s64 new_allocated_size, bw; + ntfs_volume *vol = na->ni->vol; + ATTR_REC *a = ctx->attr; + runlist *rl; + int mp_size, mp_ofs, name_ofs, arec_size, err; + + ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x.\n", (unsigned long + long)na->ni->mft_no, na->type); + + /* Some preliminary sanity checking. */ + if (NAttrNonResident(na)) { + ntfs_log_trace("Eeek! Trying to make non-resident attribute " + "non-resident. Aborting...\n"); + errno = EINVAL; + return -1; + } + + /* Check that the attribute is allowed to be non-resident. */ + if (ntfs_attr_can_be_non_resident(vol, na->type, na->name, na->name_len)) + return -1; + + new_allocated_size = (le32_to_cpu(a->value_length) + vol->cluster_size + - 1) & ~(vol->cluster_size - 1); + + if (new_allocated_size > 0) { + /* Start by allocating clusters to hold the attribute value. */ + rl = ntfs_cluster_alloc(vol, 0, new_allocated_size >> + vol->cluster_size_bits, -1, DATA_ZONE); + if (!rl) + return -1; + } else + rl = NULL; + /* + * Setup the in-memory attribute structure to be non-resident so that + * we can use ntfs_attr_pwrite(). + */ + NAttrSetNonResident(na); + na->rl = rl; + na->allocated_size = new_allocated_size; + na->data_size = na->initialized_size = le32_to_cpu(a->value_length); + /* + * FIXME: For now just clear all of these as we don't support them when + * writing. + */ + NAttrClearSparse(na); + NAttrClearEncrypted(na); + if ((a->flags & ATTR_COMPRESSION_MASK) == ATTR_IS_COMPRESSED) { + /* set compression writing parameters */ + na->compression_block_size + = 1 << (STANDARD_COMPRESSION_UNIT + vol->cluster_size_bits); + na->compression_block_clusters = 1 << STANDARD_COMPRESSION_UNIT; + } + + if (rl) { + /* Now copy the attribute value to the allocated cluster(s). */ + bw = ntfs_attr_pwrite(na, 0, le32_to_cpu(a->value_length), + (u8*)a + le16_to_cpu(a->value_offset)); + if (bw != le32_to_cpu(a->value_length)) { + err = errno; + ntfs_log_debug("Eeek! Failed to write out attribute value " + "(bw = %lli, errno = %i). " + "Aborting...\n", (long long)bw, err); + if (bw >= 0) + err = EIO; + goto cluster_free_err_out; + } + } + /* Determine the size of the mapping pairs array. */ + mp_size = ntfs_get_size_for_mapping_pairs(vol, rl, 0, INT_MAX); + if (mp_size < 0) { + err = errno; + ntfs_log_debug("Eeek! Failed to get size for mapping pairs array. " + "Aborting...\n"); + goto cluster_free_err_out; + } + /* Calculate new offsets for the name and the mapping pairs array. */ + if (na->ni->flags & FILE_ATTR_COMPRESSED) + name_ofs = (sizeof(ATTR_REC) + 7) & ~7; + else + name_ofs = (sizeof(ATTR_REC) - sizeof(a->compressed_size) + 7) & ~7; + mp_ofs = (name_ofs + a->name_length * sizeof(ntfschar) + 7) & ~7; + /* + * Determine the size of the resident part of the non-resident + * attribute record. (Not compressed thus no compressed_size element + * present.) + */ + arec_size = (mp_ofs + mp_size + 7) & ~7; + + /* Resize the resident part of the attribute record. */ + if (ntfs_attr_record_resize(ctx->mrec, a, arec_size) < 0) { + err = errno; + goto cluster_free_err_out; + } + + /* + * Convert the resident part of the attribute record to describe a + * non-resident attribute. + */ + a->non_resident = 1; + + /* Move the attribute name if it exists and update the offset. */ + if (a->name_length) + memmove((u8*)a + name_ofs, (u8*)a + le16_to_cpu(a->name_offset), + a->name_length * sizeof(ntfschar)); + a->name_offset = cpu_to_le16(name_ofs); + + /* Setup the fields specific to non-resident attributes. */ + a->lowest_vcn = cpu_to_sle64(0); + a->highest_vcn = cpu_to_sle64((new_allocated_size - 1) >> + vol->cluster_size_bits); + + a->mapping_pairs_offset = cpu_to_le16(mp_ofs); + + /* + * Update the flags to match the in-memory ones. + * However cannot change the compression state if we had + * a fuse_file_info open with a mark for release. + * The decisions about compression can only be made when + * creating/recreating the stream, not when making non resident. + */ + a->flags &= ~(ATTR_IS_SPARSE | ATTR_IS_ENCRYPTED); + if ((a->flags & ATTR_COMPRESSION_MASK) == ATTR_IS_COMPRESSED) { + /* support only ATTR_IS_COMPRESSED compression mode */ + a->compression_unit = STANDARD_COMPRESSION_UNIT; + a->compressed_size = const_cpu_to_le64(0); + } else { + a->compression_unit = 0; + a->flags &= ~ATTR_COMPRESSION_MASK; + na->data_flags = a->flags; + } + + memset(&a->reserved1, 0, sizeof(a->reserved1)); + + a->allocated_size = cpu_to_sle64(new_allocated_size); + a->data_size = a->initialized_size = cpu_to_sle64(na->data_size); + + /* Generate the mapping pairs array in the attribute record. */ + if (ntfs_mapping_pairs_build(vol, (u8*)a + mp_ofs, arec_size - mp_ofs, + rl, 0, NULL) < 0) { + // FIXME: Eeek! We need rollback! (AIA) + ntfs_log_trace("Eeek! Failed to build mapping pairs. Leaving " + "corrupt attribute record on disk. In memory " + "runlist is still intact! Error code is %i. " + "FIXME: Need to rollback instead!\n", errno); + return -1; + } + + /* Done! */ + return 0; + +cluster_free_err_out: + if (rl && ntfs_cluster_free(vol, na, 0, -1) < 0) + ntfs_log_trace("Eeek! Failed to release allocated clusters in error " + "code path. Leaving inconsistent metadata...\n"); + NAttrClearNonResident(na); + na->allocated_size = na->data_size; + na->rl = NULL; + free(rl); + errno = err; + return -1; +} + + +static int ntfs_resident_attr_resize(ntfs_attr *na, const s64 newsize); + +/** + * ntfs_resident_attr_resize - resize a resident, open ntfs attribute + * @na: resident ntfs attribute to resize + * @newsize: new size (in bytes) to which to resize the attribute + * + * Change the size of a resident, open ntfs attribute @na to @newsize bytes. + * + * On success return 0 + * On error return values are: + * STATUS_RESIDENT_ATTRIBUTE_FILLED_MFT + * STATUS_ERROR - otherwise + * The following error codes are defined: + * ENOMEM - Not enough memory to complete operation. + * ERANGE - @newsize is not valid for the attribute type of @na. + * ENOSPC - There is no enough space in base mft to resize $ATTRIBUTE_LIST. + */ +static int ntfs_resident_attr_resize_i(ntfs_attr *na, const s64 newsize) +{ + ntfs_attr_search_ctx *ctx; + ntfs_volume *vol; + ntfs_inode *ni; + int err, ret = STATUS_ERROR; + + ntfs_log_trace("Inode 0x%llx attr 0x%x new size %lld\n", + (unsigned long long)na->ni->mft_no, na->type, + (long long)newsize); + + /* Get the attribute record that needs modification. */ + ctx = ntfs_attr_get_search_ctx(na->ni, NULL); + if (!ctx) + return -1; + if (ntfs_attr_lookup(na->type, na->name, na->name_len, 0, 0, NULL, 0, + ctx)) { + err = errno; + ntfs_log_perror("ntfs_attr_lookup failed"); + goto put_err_out; + } + vol = na->ni->vol; + /* + * Check the attribute type and the corresponding minimum and maximum + * sizes against @newsize and fail if @newsize is out of bounds. + */ + if (ntfs_attr_size_bounds_check(vol, na->type, newsize) < 0) { + err = errno; + if (err == ENOENT) + err = EIO; + ntfs_log_perror("%s: bounds check failed", __FUNCTION__); + goto put_err_out; + } + /* + * If @newsize is bigger than the mft record we need to make the + * attribute non-resident if the attribute type supports it. If it is + * smaller we can go ahead and attempt the resize. + */ + if (newsize < vol->mft_record_size) { + /* Perform the resize of the attribute record. */ + if (!(ret = ntfs_resident_attr_value_resize(ctx->mrec, ctx->attr, + newsize))) { + /* Update attribute size everywhere. */ + na->data_size = na->initialized_size = newsize; + na->allocated_size = (newsize + 7) & ~7; + if ((na->data_flags & ATTR_COMPRESSION_MASK) + || NAttrSparse(na)) + na->compressed_size = na->allocated_size; + if (na->ni->mrec->flags & MFT_RECORD_IS_DIRECTORY + ? na->type == AT_INDEX_ROOT && na->name == NTFS_INDEX_I30 + : na->type == AT_DATA && na->name == AT_UNNAMED) { + na->ni->data_size = na->data_size; + na->ni->allocated_size = na->allocated_size; + set_nino_flag(na->ni,KnownSize); + if (na->type == AT_DATA) + NInoFileNameSetDirty(na->ni); + } + goto resize_done; + } + /* Prefer AT_INDEX_ALLOCATION instead of AT_ATTRIBUTE_LIST */ + if (ret == STATUS_RESIDENT_ATTRIBUTE_FILLED_MFT) { + err = errno; + goto put_err_out; + } + } + /* There is not enough space in the mft record to perform the resize. */ + + /* Make the attribute non-resident if possible. */ + if (!ntfs_attr_make_non_resident(na, ctx)) { + ntfs_inode_mark_dirty(ctx->ntfs_ino); + ntfs_attr_put_search_ctx(ctx); + /* Resize non-resident attribute */ + return ntfs_attr_truncate(na, newsize); + } else if (errno != ENOSPC && errno != EPERM) { + err = errno; + ntfs_log_perror("Failed to make attribute non-resident"); + goto put_err_out; + } + + /* Try to make other attributes non-resident and retry each time. */ + ntfs_attr_init_search_ctx(ctx, NULL, na->ni->mrec); + while (!ntfs_attr_lookup(AT_UNUSED, NULL, 0, 0, 0, NULL, 0, ctx)) { + ntfs_attr *tna; + ATTR_RECORD *a; + + a = ctx->attr; + if (a->non_resident) + continue; + + /* + * Check out whether convert is reasonable. Assume that mapping + * pairs will take 8 bytes. + */ + if (le32_to_cpu(a->length) <= offsetof(ATTR_RECORD, + compressed_size) + ((a->name_length * + sizeof(ntfschar) + 7) & ~7) + 8) + continue; + + tna = ntfs_attr_open(na->ni, a->type, (ntfschar*)((u8*)a + + le16_to_cpu(a->name_offset)), a->name_length); + if (!tna) { + err = errno; + ntfs_log_perror("Couldn't open attribute"); + goto put_err_out; + } + if (ntfs_attr_make_non_resident(tna, ctx)) { + ntfs_attr_close(tna); + continue; + } + ntfs_inode_mark_dirty(tna->ni); + ntfs_attr_close(tna); + ntfs_attr_put_search_ctx(ctx); + return ntfs_resident_attr_resize(na, newsize); + } + /* Check whether error occurred. */ + if (errno != ENOENT) { + err = errno; + ntfs_log_perror("%s: Attribute lookup failed 1", __FUNCTION__); + goto put_err_out; + } + + /* + * The standard information and attribute list attributes can't be + * moved out from the base MFT record, so try to move out others. + */ + if (na->type==AT_STANDARD_INFORMATION || na->type==AT_ATTRIBUTE_LIST) { + ntfs_attr_put_search_ctx(ctx); + if (ntfs_inode_free_space(na->ni, offsetof(ATTR_RECORD, + non_resident_end) + 8)) { + ntfs_log_perror("Could not free space in MFT record"); + return -1; + } + return ntfs_resident_attr_resize(na, newsize); + } + + /* + * Move the attribute to a new mft record, creating an attribute list + * attribute or modifying it if it is already present. + */ + + /* Point search context back to attribute which we need resize. */ + ntfs_attr_init_search_ctx(ctx, na->ni, NULL); + if (ntfs_attr_lookup(na->type, na->name, na->name_len, CASE_SENSITIVE, + 0, NULL, 0, ctx)) { + ntfs_log_perror("%s: Attribute lookup failed 2", __FUNCTION__); + err = errno; + goto put_err_out; + } + + /* + * Check whether attribute is already single in this MFT record. + * 8 added for the attribute terminator. + */ + if (le32_to_cpu(ctx->mrec->bytes_in_use) == + le16_to_cpu(ctx->mrec->attrs_offset) + + le32_to_cpu(ctx->attr->length) + 8) { + err = ENOSPC; + ntfs_log_trace("MFT record is filled with one attribute\n"); + ret = STATUS_RESIDENT_ATTRIBUTE_FILLED_MFT; + goto put_err_out; + } + + /* Add attribute list if not present. */ + if (na->ni->nr_extents == -1) + ni = na->ni->base_ni; + else + ni = na->ni; + if (!NInoAttrList(ni)) { + ntfs_attr_put_search_ctx(ctx); + if (ntfs_inode_add_attrlist(ni)) + return -1; + return ntfs_resident_attr_resize(na, newsize); + } + /* Allocate new mft record. */ + ni = ntfs_mft_record_alloc(vol, ni); + if (!ni) { + err = errno; + ntfs_log_perror("Couldn't allocate new MFT record"); + goto put_err_out; + } + /* Move attribute to it. */ + if (ntfs_attr_record_move_to(ctx, ni)) { + err = errno; + ntfs_log_perror("Couldn't move attribute to new MFT record"); + goto put_err_out; + } + /* Update ntfs attribute. */ + if (na->ni->nr_extents == -1) + na->ni = ni; + + ntfs_attr_put_search_ctx(ctx); + /* Try to perform resize once again. */ + return ntfs_resident_attr_resize(na, newsize); + +resize_done: + /* + * Set the inode (and its base inode if it exists) dirty so it is + * written out later. + */ + ntfs_inode_mark_dirty(ctx->ntfs_ino); + ntfs_attr_put_search_ctx(ctx); + return 0; +put_err_out: + ntfs_attr_put_search_ctx(ctx); + errno = err; + return ret; +} + +static int ntfs_resident_attr_resize(ntfs_attr *na, const s64 newsize) +{ + int ret; + + ntfs_log_enter("Entering\n"); + ret = ntfs_resident_attr_resize_i(na, newsize); + ntfs_log_leave("\n"); + return ret; +} + +/** + * ntfs_attr_make_resident - convert a non-resident to a resident attribute + * @na: open ntfs attribute to make resident + * @ctx: ntfs search context describing the attribute + * + * Convert a non-resident ntfs attribute to a resident one. + * + * Return 0 on success and -1 on error with errno set to the error code. The + * following error codes are defined: + * EINVAL - Invalid arguments passed. + * EPERM - The attribute is not allowed to be resident. + * EIO - I/O error, damaged inode or bug. + * ENOSPC - There is no enough space to perform conversion. + * EOPNOTSUPP - Requested conversion is not supported yet. + * + * Warning: We do not set the inode dirty and we do not write out anything! + * We expect the caller to do this as this is a fairly low level + * function and it is likely there will be further changes made. + */ +static int ntfs_attr_make_resident(ntfs_attr *na, ntfs_attr_search_ctx *ctx) +{ + ntfs_volume *vol = na->ni->vol; + ATTR_REC *a = ctx->attr; + int name_ofs, val_ofs, err = EIO; + s64 arec_size, bytes_read; + + ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x.\n", (unsigned long + long)na->ni->mft_no, na->type); + + /* Should be called for the first extent of the attribute. */ + if (sle64_to_cpu(a->lowest_vcn)) { + ntfs_log_trace("Eeek! Should be called for the first extent of the " + "attribute. Aborting...\n"); + errno = EINVAL; + return -1; + } + + /* Some preliminary sanity checking. */ + if (!NAttrNonResident(na)) { + ntfs_log_trace("Eeek! Trying to make resident attribute resident. " + "Aborting...\n"); + errno = EINVAL; + return -1; + } + + /* Make sure this is not $MFT/$BITMAP or Windows will not boot! */ + if (na->type == AT_BITMAP && na->ni->mft_no == FILE_MFT) { + errno = EPERM; + return -1; + } + + /* Check that the attribute is allowed to be resident. */ + if (ntfs_attr_can_be_resident(vol, na->type)) + return -1; + + if (na->data_flags & ATTR_IS_ENCRYPTED) { + ntfs_log_trace("Making encrypted streams resident is not " + "implemented yet.\n"); + errno = EOPNOTSUPP; + return -1; + } + + /* Work out offsets into and size of the resident attribute. */ + name_ofs = 24; /* = sizeof(resident_ATTR_REC); */ + val_ofs = (name_ofs + a->name_length * sizeof(ntfschar) + 7) & ~7; + arec_size = (val_ofs + na->data_size + 7) & ~7; + + /* Sanity check the size before we start modifying the attribute. */ + if (le32_to_cpu(ctx->mrec->bytes_in_use) - le32_to_cpu(a->length) + + arec_size > le32_to_cpu(ctx->mrec->bytes_allocated)) { + errno = ENOSPC; + ntfs_log_trace("Not enough space to make attribute resident\n"); + return -1; + } + + /* Read and cache the whole runlist if not already done. */ + if (ntfs_attr_map_whole_runlist(na)) + return -1; + + /* Move the attribute name if it exists and update the offset. */ + if (a->name_length) { + memmove((u8*)a + name_ofs, (u8*)a + le16_to_cpu(a->name_offset), + a->name_length * sizeof(ntfschar)); + } + a->name_offset = cpu_to_le16(name_ofs); + + /* Resize the resident part of the attribute record. */ + if (ntfs_attr_record_resize(ctx->mrec, a, arec_size) < 0) { + /* + * Bug, because ntfs_attr_record_resize should not fail (we + * already checked that attribute fits MFT record). + */ + ntfs_log_error("BUG! Failed to resize attribute record. " + "Please report to the %s. Aborting...\n", + NTFS_DEV_LIST); + errno = EIO; + return -1; + } + + /* Convert the attribute record to describe a resident attribute. */ + a->non_resident = 0; + a->flags = 0; + a->value_length = cpu_to_le32(na->data_size); + a->value_offset = cpu_to_le16(val_ofs); + /* + * If a data stream was wiped out, adjust the compression mode + * to current state of compression flag + */ + if (!na->data_size + && (na->type == AT_DATA) + && (na->ni->vol->cluster_size <= MAX_COMPRESSION_CLUSTER_SIZE) + && (na->ni->flags & FILE_ATTR_COMPRESSED)) { + a->flags |= ATTR_IS_COMPRESSED; + na->data_flags = a->flags; + } + /* + * File names cannot be non-resident so we would never see this here + * but at least it serves as a reminder that there may be attributes + * for which we do need to set this flag. (AIA) + */ + if (a->type == AT_FILE_NAME) + a->resident_flags = RESIDENT_ATTR_IS_INDEXED; + else + a->resident_flags = 0; + a->reservedR = 0; + + /* Sanity fixup... Shouldn't really happen. (AIA) */ + if (na->initialized_size > na->data_size) + na->initialized_size = na->data_size; + + /* Copy data from run list to resident attribute value. */ + bytes_read = ntfs_rl_pread(vol, na->rl, 0, na->initialized_size, + (u8*)a + val_ofs); + if (bytes_read != na->initialized_size) { + if (bytes_read < 0) + err = errno; + ntfs_log_trace("Eeek! Failed to read attribute data. Leaving " + "inconstant metadata. Run chkdsk. " + "Aborting...\n"); + errno = err; + return -1; + } + + /* Clear memory in gap between initialized_size and data_size. */ + if (na->initialized_size < na->data_size) + memset((u8*)a + val_ofs + na->initialized_size, 0, + na->data_size - na->initialized_size); + + /* + * Deallocate clusters from the runlist. + * + * NOTE: We can use ntfs_cluster_free() because we have already mapped + * the whole run list and thus it doesn't matter that the attribute + * record is in a transiently corrupted state at this moment in time. + */ + if (ntfs_cluster_free(vol, na, 0, -1) < 0) { + err = errno; + ntfs_log_perror("Eeek! Failed to release allocated clusters"); + ntfs_log_trace("Ignoring error and leaving behind wasted " + "clusters.\n"); + } + + /* Throw away the now unused runlist. */ + free(na->rl); + na->rl = NULL; + + /* Update in-memory struct ntfs_attr. */ + NAttrClearNonResident(na); + NAttrClearSparse(na); + NAttrClearEncrypted(na); + na->initialized_size = na->data_size; + na->allocated_size = na->compressed_size = (na->data_size + 7) & ~7; + na->compression_block_size = 0; + na->compression_block_size_bits = na->compression_block_clusters = 0; + return 0; +} + +/* + * If we are in the first extent, then set/clean sparse bit, + * update allocated and compressed size. + */ +static int ntfs_attr_update_meta(ATTR_RECORD *a, ntfs_attr *na, MFT_RECORD *m, + ntfs_attr_search_ctx *ctx) +{ + int sparse, ret = 0; + + ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x\n", + (unsigned long long)na->ni->mft_no, na->type); + + if (a->lowest_vcn) + goto out; + + a->allocated_size = cpu_to_sle64(na->allocated_size); + + /* Update sparse bit. */ + sparse = ntfs_rl_sparse(na->rl); + if (sparse == -1) { + errno = EIO; + goto error; + } + + /* Attribute become sparse. */ + if (sparse && !(a->flags & (ATTR_IS_SPARSE | ATTR_IS_COMPRESSED))) { + /* + * Move attribute to another mft record, if attribute is too + * small to add compressed_size field to it and we have no + * free space in the current mft record. + */ + if ((le32_to_cpu(a->length) - + le16_to_cpu(a->mapping_pairs_offset) == 8) + && !(le32_to_cpu(m->bytes_allocated) - + le32_to_cpu(m->bytes_in_use))) { + + if (!NInoAttrList(na->ni)) { + ntfs_attr_put_search_ctx(ctx); + if (ntfs_inode_add_attrlist(na->ni)) + goto leave; + goto retry; + } + if (ntfs_attr_record_move_away(ctx, 8)) { + ntfs_log_perror("Failed to move attribute"); + goto error; + } + ntfs_attr_put_search_ctx(ctx); + goto retry; + } + if (!(le32_to_cpu(a->length) - le16_to_cpu( + a->mapping_pairs_offset))) { + errno = EIO; + ntfs_log_perror("Mapping pairs space is 0"); + goto error; + } + + NAttrSetSparse(na); + a->flags |= ATTR_IS_SPARSE; + a->compression_unit = STANDARD_COMPRESSION_UNIT; /* Windows + set it so, even if attribute is not actually compressed. */ + + memmove((u8*)a + le16_to_cpu(a->name_offset) + 8, + (u8*)a + le16_to_cpu(a->name_offset), + a->name_length * sizeof(ntfschar)); + + a->name_offset = cpu_to_le16(le16_to_cpu(a->name_offset) + 8); + + a->mapping_pairs_offset = + cpu_to_le16(le16_to_cpu(a->mapping_pairs_offset) + 8); + } + + /* Attribute no longer sparse. */ + if (!sparse && (a->flags & ATTR_IS_SPARSE) && + !(a->flags & ATTR_IS_COMPRESSED)) { + + NAttrClearSparse(na); + a->flags &= ~ATTR_IS_SPARSE; + a->compression_unit = 0; + + memmove((u8*)a + le16_to_cpu(a->name_offset) - 8, + (u8*)a + le16_to_cpu(a->name_offset), + a->name_length * sizeof(ntfschar)); + + if (le16_to_cpu(a->name_offset) >= 8) + a->name_offset = cpu_to_le16(le16_to_cpu(a->name_offset) - 8); + + a->mapping_pairs_offset = + cpu_to_le16(le16_to_cpu(a->mapping_pairs_offset) - 8); + } + + /* Update compressed size if required. */ + if (sparse || (na->data_flags & ATTR_COMPRESSION_MASK)) { + s64 new_compr_size; + + new_compr_size = ntfs_rl_get_compressed_size(na->ni->vol, na->rl); + if (new_compr_size == -1) + goto error; + + na->compressed_size = new_compr_size; + a->compressed_size = cpu_to_sle64(new_compr_size); + } + /* + * Set FILE_NAME dirty flag, to update sparse bit and + * allocated size in the index. + */ + if (na->type == AT_DATA && na->name == AT_UNNAMED) { + if (sparse) + na->ni->allocated_size = na->compressed_size; + else + na->ni->allocated_size = na->allocated_size; + NInoFileNameSetDirty(na->ni); + } +out: + return ret; +leave: ret = -1; goto out; /* return -1 */ +retry: ret = -2; goto out; +error: ret = -3; goto out; +} + +#define NTFS_VCN_DELETE_MARK -2 +/** + * ntfs_attr_update_mapping_pairs_i - see ntfs_attr_update_mapping_pairs + */ +static int ntfs_attr_update_mapping_pairs_i(ntfs_attr *na, VCN from_vcn) +{ + ntfs_attr_search_ctx *ctx; + ntfs_inode *ni, *base_ni; + MFT_RECORD *m; + ATTR_RECORD *a; + VCN stop_vcn; + const runlist_element *stop_rl; + int err, mp_size, cur_max_mp_size, exp_max_mp_size, ret = -1; + BOOL finished_build; + +retry: + if (!na || !na->rl || from_vcn) { + errno = EINVAL; + ntfs_log_perror("%s: na=%p", __FUNCTION__, na); + return -1; + } + + ntfs_log_trace("Entering for inode %llu, attr 0x%x\n", + (unsigned long long)na->ni->mft_no, na->type); + + if (!NAttrNonResident(na)) { + errno = EINVAL; + ntfs_log_perror("%s: resident attribute", __FUNCTION__); + return -1; + } + + if (na->ni->nr_extents == -1) + base_ni = na->ni->base_ni; + else + base_ni = na->ni; + + ctx = ntfs_attr_get_search_ctx(base_ni, NULL); + if (!ctx) + return -1; + + /* Fill attribute records with new mapping pairs. */ + stop_vcn = 0; + stop_rl = na->rl; + finished_build = FALSE; + while (!ntfs_attr_lookup(na->type, na->name, na->name_len, + CASE_SENSITIVE, from_vcn, NULL, 0, ctx)) { + a = ctx->attr; + m = ctx->mrec; + /* + * If runlist is updating not from the beginning, then set + * @stop_vcn properly, i.e. to the lowest vcn of record that + * contain @from_vcn. Also we do not need @from_vcn anymore, + * set it to 0 to make ntfs_attr_lookup enumerate attributes. + */ + if (from_vcn) { + LCN first_lcn; + + stop_vcn = sle64_to_cpu(a->lowest_vcn); + from_vcn = 0; + /* + * Check whether the first run we need to update is + * the last run in runlist, if so, then deallocate + * all attrubute extents starting this one. + */ + first_lcn = ntfs_rl_vcn_to_lcn(na->rl, stop_vcn); + if (first_lcn == LCN_EINVAL) { + errno = EIO; + ntfs_log_perror("Bad runlist"); + goto put_err_out; + } + if (first_lcn == LCN_ENOENT || + first_lcn == LCN_RL_NOT_MAPPED) + finished_build = TRUE; + } + + /* + * Check whether we finished mapping pairs build, if so mark + * extent as need to delete (by setting highest vcn to + * NTFS_VCN_DELETE_MARK (-2), we shall check it later and + * delete extent) and continue search. + */ + if (finished_build) { + ntfs_log_trace("Mark attr 0x%x for delete in inode " + "%lld.\n", (unsigned)le32_to_cpu(a->type), + (long long)ctx->ntfs_ino->mft_no); + a->highest_vcn = cpu_to_sle64(NTFS_VCN_DELETE_MARK); + ntfs_inode_mark_dirty(ctx->ntfs_ino); + continue; + } + + switch (ntfs_attr_update_meta(a, na, m, ctx)) { + case -1: return -1; + case -2: goto retry; + case -3: goto put_err_out; + } + + /* + * Determine maximum possible length of mapping pairs, + * if we shall *not* expand space for mapping pairs. + */ + cur_max_mp_size = le32_to_cpu(a->length) - + le16_to_cpu(a->mapping_pairs_offset); + /* + * Determine maximum possible length of mapping pairs in the + * current mft record, if we shall expand space for mapping + * pairs. + */ + exp_max_mp_size = le32_to_cpu(m->bytes_allocated) - + le32_to_cpu(m->bytes_in_use) + cur_max_mp_size; + /* Get the size for the rest of mapping pairs array. */ + mp_size = ntfs_get_size_for_mapping_pairs(na->ni->vol, stop_rl, + stop_vcn, exp_max_mp_size); + if (mp_size <= 0) { + ntfs_log_perror("%s: get MP size failed", __FUNCTION__); + goto put_err_out; + } + /* Test mapping pairs for fitting in the current mft record. */ + if (mp_size > exp_max_mp_size) { + /* + * Mapping pairs of $ATTRIBUTE_LIST attribute must fit + * in the base mft record. Try to move out other + * attributes and try again. + */ + if (na->type == AT_ATTRIBUTE_LIST) { + ntfs_attr_put_search_ctx(ctx); + if (ntfs_inode_free_space(na->ni, mp_size - + cur_max_mp_size)) { + ntfs_log_perror("Attribute list is too " + "big. Defragment the " + "volume\n"); + return -1; + } + goto retry; + } + + /* Add attribute list if it isn't present, and retry. */ + if (!NInoAttrList(base_ni)) { + ntfs_attr_put_search_ctx(ctx); + if (ntfs_inode_add_attrlist(base_ni)) { + ntfs_log_perror("Can not add attrlist"); + return -1; + } + goto retry; + } + + /* + * Set mapping pairs size to maximum possible for this + * mft record. We shall write the rest of mapping pairs + * to another MFT records. + */ + mp_size = exp_max_mp_size; + } + + /* Change space for mapping pairs if we need it. */ + if (((mp_size + 7) & ~7) != cur_max_mp_size) { + if (ntfs_attr_record_resize(m, a, + le16_to_cpu(a->mapping_pairs_offset) + + mp_size)) { + errno = EIO; + ntfs_log_perror("Failed to resize attribute"); + goto put_err_out; + } + } + + /* Update lowest vcn. */ + a->lowest_vcn = cpu_to_sle64(stop_vcn); + ntfs_inode_mark_dirty(ctx->ntfs_ino); + if ((ctx->ntfs_ino->nr_extents == -1 || + NInoAttrList(ctx->ntfs_ino)) && + ctx->attr->type != AT_ATTRIBUTE_LIST) { + ctx->al_entry->lowest_vcn = cpu_to_sle64(stop_vcn); + ntfs_attrlist_mark_dirty(ctx->ntfs_ino); + } + + /* + * Generate the new mapping pairs array directly into the + * correct destination, i.e. the attribute record itself. + */ + if (!ntfs_mapping_pairs_build(na->ni->vol, (u8*)a + le16_to_cpu( + a->mapping_pairs_offset), mp_size, na->rl, + stop_vcn, &stop_rl)) + finished_build = TRUE; + if (stop_rl) + stop_vcn = stop_rl->vcn; + else + stop_vcn = 0; + if (!finished_build && errno != ENOSPC) { + ntfs_log_perror("Failed to build mapping pairs"); + goto put_err_out; + } + a->highest_vcn = cpu_to_sle64(stop_vcn - 1); + } + /* Check whether error occurred. */ + if (errno != ENOENT) { + ntfs_log_perror("%s: Attribute lookup failed", __FUNCTION__); + goto put_err_out; + } + + /* Deallocate not used attribute extents and return with success. */ + if (finished_build) { + ntfs_attr_reinit_search_ctx(ctx); + ntfs_log_trace("Deallocate marked extents.\n"); + while (!ntfs_attr_lookup(na->type, na->name, na->name_len, + CASE_SENSITIVE, 0, NULL, 0, ctx)) { + if (sle64_to_cpu(ctx->attr->highest_vcn) != + NTFS_VCN_DELETE_MARK) + continue; + /* Remove unused attribute record. */ + if (ntfs_attr_record_rm(ctx)) { + ntfs_log_perror("Could not remove unused attr"); + goto put_err_out; + } + ntfs_attr_reinit_search_ctx(ctx); + } + if (errno != ENOENT) { + ntfs_log_perror("%s: Attr lookup failed", __FUNCTION__); + goto put_err_out; + } + ntfs_log_trace("Deallocate done.\n"); + ntfs_attr_put_search_ctx(ctx); + goto ok; + } + ntfs_attr_put_search_ctx(ctx); + ctx = NULL; + + /* Allocate new MFT records for the rest of mapping pairs. */ + while (1) { + /* Calculate size of rest mapping pairs. */ + mp_size = ntfs_get_size_for_mapping_pairs(na->ni->vol, + na->rl, stop_vcn, INT_MAX); + if (mp_size <= 0) { + ntfs_log_perror("%s: get mp size failed", __FUNCTION__); + goto put_err_out; + } + /* Allocate new mft record. */ + ni = ntfs_mft_record_alloc(na->ni->vol, base_ni); + if (!ni) { + ntfs_log_perror("Could not allocate new MFT record"); + goto put_err_out; + } + m = ni->mrec; + /* + * If mapping size exceed available space, set them to + * possible maximum. + */ + cur_max_mp_size = le32_to_cpu(m->bytes_allocated) - + le32_to_cpu(m->bytes_in_use) - + (offsetof(ATTR_RECORD, compressed_size) + + (((na->data_flags & ATTR_COMPRESSION_MASK) + || NAttrSparse(na)) ? + sizeof(a->compressed_size) : 0)) - + ((sizeof(ntfschar) * na->name_len + 7) & ~7); + if (mp_size > cur_max_mp_size) + mp_size = cur_max_mp_size; + /* Add attribute extent to new record. */ + err = ntfs_non_resident_attr_record_add(ni, na->type, + na->name, na->name_len, stop_vcn, mp_size, + na->data_flags); + if (err == -1) { + err = errno; + ntfs_log_perror("Could not add attribute extent"); + if (ntfs_mft_record_free(na->ni->vol, ni)) + ntfs_log_perror("Could not free MFT record"); + errno = err; + goto put_err_out; + } + a = (ATTR_RECORD*)((u8*)m + err); + + err = ntfs_mapping_pairs_build(na->ni->vol, (u8*)a + + le16_to_cpu(a->mapping_pairs_offset), mp_size, na->rl, + stop_vcn, &stop_rl); + if (stop_rl) + stop_vcn = stop_rl->vcn; + else + stop_vcn = 0; + if (err < 0 && errno != ENOSPC) { + err = errno; + ntfs_log_perror("Failed to build MP"); + if (ntfs_mft_record_free(na->ni->vol, ni)) + ntfs_log_perror("Couldn't free MFT record"); + errno = err; + goto put_err_out; + } + a->highest_vcn = cpu_to_sle64(stop_vcn - 1); + ntfs_inode_mark_dirty(ni); + /* All mapping pairs has been written. */ + if (!err) + break; + } +ok: + ret = 0; +out: + return ret; +put_err_out: + if (ctx) + ntfs_attr_put_search_ctx(ctx); + goto out; +} +#undef NTFS_VCN_DELETE_MARK + +/** + * ntfs_attr_update_mapping_pairs - update mapping pairs for ntfs attribute + * @na: non-resident ntfs open attribute for which we need update + * @from_vcn: update runlist starting this VCN + * + * Build mapping pairs from @na->rl and write them to the disk. Also, this + * function updates sparse bit, allocated and compressed size (allocates/frees + * space for this field if required). + * + * @na->allocated_size should be set to correct value for the new runlist before + * call to this function. Vice-versa @na->compressed_size will be calculated and + * set to correct value during this function. + * + * FIXME: This function does not update sparse bit and compressed size correctly + * if called with @from_vcn != 0. + * + * FIXME: Rewrite without using NTFS_VCN_DELETE_MARK define. + * + * On success return 0 and on error return -1 with errno set to the error code. + * The following error codes are defined: + * EINVAL - Invalid arguments passed. + * ENOMEM - Not enough memory to complete operation. + * ENOSPC - There is no enough space in base mft to resize $ATTRIBUTE_LIST + * or there is no free MFT records left to allocate. + */ +int ntfs_attr_update_mapping_pairs(ntfs_attr *na, VCN from_vcn) +{ + int ret; + + ntfs_log_enter("Entering\n"); + ret = ntfs_attr_update_mapping_pairs_i(na, from_vcn); + ntfs_log_leave("\n"); + return ret; +} + +/** + * ntfs_non_resident_attr_shrink - shrink a non-resident, open ntfs attribute + * @na: non-resident ntfs attribute to shrink + * @newsize: new size (in bytes) to which to shrink the attribute + * + * Reduce the size of a non-resident, open ntfs attribute @na to @newsize bytes. + * + * On success return 0 and on error return -1 with errno set to the error code. + * The following error codes are defined: + * ENOMEM - Not enough memory to complete operation. + * ERANGE - @newsize is not valid for the attribute type of @na. + */ +static int ntfs_non_resident_attr_shrink(ntfs_attr *na, const s64 newsize) +{ + ntfs_volume *vol; + ntfs_attr_search_ctx *ctx; + VCN first_free_vcn; + s64 nr_freed_clusters; + int err; + + ntfs_log_trace("Inode 0x%llx attr 0x%x new size %lld\n", (unsigned long long) + na->ni->mft_no, na->type, (long long)newsize); + + vol = na->ni->vol; + + /* + * Check the attribute type and the corresponding minimum size + * against @newsize and fail if @newsize is too small. + */ + if (ntfs_attr_size_bounds_check(vol, na->type, newsize) < 0) { + if (errno == ERANGE) { + ntfs_log_trace("Eeek! Size bounds check failed. " + "Aborting...\n"); + } else if (errno == ENOENT) + errno = EIO; + return -1; + } + + /* The first cluster outside the new allocation. */ + first_free_vcn = (newsize + vol->cluster_size - 1) >> + vol->cluster_size_bits; + /* + * Compare the new allocation with the old one and only deallocate + * clusters if there is a change. + */ + if ((na->allocated_size >> vol->cluster_size_bits) != first_free_vcn) { + if (ntfs_attr_map_whole_runlist(na)) { + ntfs_log_trace("Eeek! ntfs_attr_map_whole_runlist " + "failed.\n"); + return -1; + } + /* Deallocate all clusters starting with the first free one. */ + nr_freed_clusters = ntfs_cluster_free(vol, na, first_free_vcn, + -1); + if (nr_freed_clusters < 0) { + ntfs_log_trace("Eeek! Freeing of clusters failed. " + "Aborting...\n"); + return -1; + } + + /* Truncate the runlist itself. */ + if (ntfs_rl_truncate(&na->rl, first_free_vcn)) { + /* + * Failed to truncate the runlist, so just throw it + * away, it will be mapped afresh on next use. + */ + free(na->rl); + na->rl = NULL; + ntfs_log_trace("Eeek! Run list truncation failed.\n"); + return -1; + } + + /* Prepare to mapping pairs update. */ + na->allocated_size = first_free_vcn << vol->cluster_size_bits; + /* Write mapping pairs for new runlist. */ + if (ntfs_attr_update_mapping_pairs(na, 0 /*first_free_vcn*/)) { + ntfs_log_trace("Eeek! Mapping pairs update failed. " + "Leaving inconstant metadata. " + "Run chkdsk.\n"); + return -1; + } + } + + /* Get the first attribute record. */ + ctx = ntfs_attr_get_search_ctx(na->ni, NULL); + if (!ctx) + return -1; + + if (ntfs_attr_lookup(na->type, na->name, na->name_len, CASE_SENSITIVE, + 0, NULL, 0, ctx)) { + err = errno; + if (err == ENOENT) + err = EIO; + ntfs_log_trace("Eeek! Lookup of first attribute extent failed. " + "Leaving inconstant metadata.\n"); + goto put_err_out; + } + + /* Update data and initialized size. */ + na->data_size = newsize; + ctx->attr->data_size = cpu_to_sle64(newsize); + if (newsize < na->initialized_size) { + na->initialized_size = newsize; + ctx->attr->initialized_size = cpu_to_sle64(newsize); + } + /* Update data size in the index. */ + if (na->ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) { + if (na->type == AT_INDEX_ROOT && na->name == NTFS_INDEX_I30) { + na->ni->data_size = na->data_size; + na->ni->allocated_size = na->allocated_size; + set_nino_flag(na->ni,KnownSize); + } + } else { + if (na->type == AT_DATA && na->name == AT_UNNAMED) { + na->ni->data_size = na->data_size; + NInoFileNameSetDirty(na->ni); + } + } + + /* If the attribute now has zero size, make it resident. */ + if (!newsize) { + if (ntfs_attr_make_resident(na, ctx)) { + /* If couldn't make resident, just continue. */ + if (errno != EPERM) + ntfs_log_error("Failed to make attribute " + "resident. Leaving as is...\n"); + } + } + + /* Set the inode dirty so it is written out later. */ + ntfs_inode_mark_dirty(ctx->ntfs_ino); + /* Done! */ + ntfs_attr_put_search_ctx(ctx); + return 0; +put_err_out: + ntfs_attr_put_search_ctx(ctx); + errno = err; + return -1; +} + +/** + * ntfs_non_resident_attr_expand - expand a non-resident, open ntfs attribute + * @na: non-resident ntfs attribute to expand + * @newsize: new size (in bytes) to which to expand the attribute + * + * Expand the size of a non-resident, open ntfs attribute @na to @newsize bytes, + * by allocating new clusters. + * + * On success return 0 and on error return -1 with errno set to the error code. + * The following error codes are defined: + * ENOMEM - Not enough memory to complete operation. + * ERANGE - @newsize is not valid for the attribute type of @na. + * ENOSPC - There is no enough space in base mft to resize $ATTRIBUTE_LIST. + */ +static int ntfs_non_resident_attr_expand_i(ntfs_attr *na, const s64 newsize) +{ + LCN lcn_seek_from; + VCN first_free_vcn; + ntfs_volume *vol; + ntfs_attr_search_ctx *ctx; + runlist *rl, *rln; + s64 org_alloc_size; + int err; + + ntfs_log_trace("Inode %lld, attr 0x%x, new size %lld old size %lld\n", + (unsigned long long)na->ni->mft_no, na->type, + (long long)newsize, (long long)na->data_size); + + vol = na->ni->vol; + + /* + * Check the attribute type and the corresponding maximum size + * against @newsize and fail if @newsize is too big. + */ + if (ntfs_attr_size_bounds_check(vol, na->type, newsize) < 0) { + if (errno == ENOENT) + errno = EIO; + ntfs_log_perror("%s: bounds check failed", __FUNCTION__); + return -1; + } + + /* Save for future use. */ + org_alloc_size = na->allocated_size; + /* The first cluster outside the new allocation. */ + first_free_vcn = (newsize + vol->cluster_size - 1) >> + vol->cluster_size_bits; + /* + * Compare the new allocation with the old one and only allocate + * clusters if there is a change. + */ + if ((na->allocated_size >> vol->cluster_size_bits) < first_free_vcn) { + if (ntfs_attr_map_whole_runlist(na)) { + ntfs_log_perror("ntfs_attr_map_whole_runlist failed"); + return -1; + } + + /* + * If we extend $DATA attribute on NTFS 3+ volume, we can add + * sparse runs instead of real allocation of clusters. + */ + if (na->type == AT_DATA && vol->major_ver >= 3) { + rl = ntfs_malloc(0x1000); + if (!rl) + return -1; + + rl[0].vcn = (na->allocated_size >> + vol->cluster_size_bits); + rl[0].lcn = LCN_HOLE; + rl[0].length = first_free_vcn - + (na->allocated_size >> vol->cluster_size_bits); + rl[1].vcn = first_free_vcn; + rl[1].lcn = LCN_ENOENT; + rl[1].length = 0; + } else { + /* + * Determine first after last LCN of attribute. + * We will start seek clusters from this LCN to avoid + * fragmentation. If there are no valid LCNs in the + * attribute let the cluster allocator choose the + * starting LCN. + */ + lcn_seek_from = -1; + if (na->rl->length) { + /* Seek to the last run list element. */ + for (rl = na->rl; (rl + 1)->length; rl++) + ; + /* + * If the last LCN is a hole or similar seek + * back to last valid LCN. + */ + while (rl->lcn < 0 && rl != na->rl) + rl--; + /* + * Only set lcn_seek_from it the LCN is valid. + */ + if (rl->lcn >= 0) + lcn_seek_from = rl->lcn + rl->length; + } + + rl = ntfs_cluster_alloc(vol, na->allocated_size >> + vol->cluster_size_bits, first_free_vcn - + (na->allocated_size >> + vol->cluster_size_bits), lcn_seek_from, + DATA_ZONE); + if (!rl) { + ntfs_log_perror("Cluster allocation failed " + "(%lld)", + (long long)first_free_vcn - + ((long long)na->allocated_size >> + vol->cluster_size_bits)); + return -1; + } + } + + /* Append new clusters to attribute runlist. */ + rln = ntfs_runlists_merge(na->rl, rl); + if (!rln) { + /* Failed, free just allocated clusters. */ + err = errno; + ntfs_log_perror("Run list merge failed"); + ntfs_cluster_free_from_rl(vol, rl); + free(rl); + errno = err; + return -1; + } + na->rl = rln; + + /* Prepare to mapping pairs update. */ + na->allocated_size = first_free_vcn << vol->cluster_size_bits; + /* Write mapping pairs for new runlist. */ + if (ntfs_attr_update_mapping_pairs(na, 0 /*na->allocated_size >> + vol->cluster_size_bits*/)) { + err = errno; + ntfs_log_perror("Mapping pairs update failed"); + goto rollback; + } + } + + ctx = ntfs_attr_get_search_ctx(na->ni, NULL); + if (!ctx) { + err = errno; + if (na->allocated_size == org_alloc_size) { + errno = err; + return -1; + } else + goto rollback; + } + + if (ntfs_attr_lookup(na->type, na->name, na->name_len, CASE_SENSITIVE, + 0, NULL, 0, ctx)) { + err = errno; + ntfs_log_perror("Lookup of first attribute extent failed"); + if (err == ENOENT) + err = EIO; + if (na->allocated_size != org_alloc_size) { + ntfs_attr_put_search_ctx(ctx); + goto rollback; + } else + goto put_err_out; + } + + /* Update data size. */ + na->data_size = newsize; + ctx->attr->data_size = cpu_to_sle64(newsize); + /* Update data size in the index. */ + if (na->ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) { + if (na->type == AT_INDEX_ROOT && na->name == NTFS_INDEX_I30) { + na->ni->data_size = na->data_size; + na->ni->allocated_size = na->allocated_size; + set_nino_flag(na->ni,KnownSize); + } + } else { + if (na->type == AT_DATA && na->name == AT_UNNAMED) { + na->ni->data_size = na->data_size; + NInoFileNameSetDirty(na->ni); + } + } + /* Set the inode dirty so it is written out later. */ + ntfs_inode_mark_dirty(ctx->ntfs_ino); + /* Done! */ + ntfs_attr_put_search_ctx(ctx); + return 0; +rollback: + /* Free allocated clusters. */ + if (ntfs_cluster_free(vol, na, org_alloc_size >> + vol->cluster_size_bits, -1) < 0) { + err = EIO; + ntfs_log_perror("Leaking clusters"); + } + /* Now, truncate the runlist itself. */ + if (ntfs_rl_truncate(&na->rl, org_alloc_size >> + vol->cluster_size_bits)) { + /* + * Failed to truncate the runlist, so just throw it away, it + * will be mapped afresh on next use. + */ + free(na->rl); + na->rl = NULL; + ntfs_log_perror("Couldn't truncate runlist. Rollback failed"); + } else { + /* Prepare to mapping pairs update. */ + na->allocated_size = org_alloc_size; + /* Restore mapping pairs. */ + if (ntfs_attr_update_mapping_pairs(na, 0 /*na->allocated_size >> + vol->cluster_size_bits*/)) { + ntfs_log_perror("Failed to restore old mapping pairs"); + } + } + errno = err; + return -1; +put_err_out: + ntfs_attr_put_search_ctx(ctx); + errno = err; + return -1; +} + + +static int ntfs_non_resident_attr_expand(ntfs_attr *na, const s64 newsize) +{ + int ret; + + ntfs_log_enter("Entering\n"); + ret = ntfs_non_resident_attr_expand_i(na, newsize); + ntfs_log_leave("\n"); + return ret; +} + +/** + * ntfs_attr_truncate - resize an ntfs attribute + * @na: open ntfs attribute to resize + * @newsize: new size (in bytes) to which to resize the attribute + * + * Change the size of an open ntfs attribute @na to @newsize bytes. If the + * attribute is made bigger and the attribute is resident the newly + * "allocated" space is cleared and if the attribute is non-resident the + * newly allocated space is marked as not initialised and no real allocation + * on disk is performed. + * + * On success return 0. + * On error return values are: + * STATUS_RESIDENT_ATTRIBUTE_FILLED_MFT + * STATUS_ERROR - otherwise + * The following error codes are defined: + * EINVAL - Invalid arguments were passed to the function. + * EOPNOTSUPP - The desired resize is not implemented yet. + * EACCES - Encrypted attribute. + */ +int ntfs_attr_truncate(ntfs_attr *na, const s64 newsize) +{ + int ret = STATUS_ERROR; + s64 fullsize; + BOOL compressed; + + if (!na || newsize < 0 || + (na->ni->mft_no == FILE_MFT && na->type == AT_DATA)) { + ntfs_log_trace("Invalid arguments passed.\n"); + errno = EINVAL; + return STATUS_ERROR; + } + + ntfs_log_enter("Entering for inode %lld, attr 0x%x, size %lld\n", + (unsigned long long)na->ni->mft_no, na->type, + (long long)newsize); + + if (na->data_size == newsize) { + ntfs_log_trace("Size is already ok\n"); + ret = STATUS_OK; + goto out; + } + /* + * Encrypted attributes are not supported. We return access denied, + * which is what Windows NT4 does, too. + */ + if (na->data_flags & ATTR_IS_ENCRYPTED) { + errno = EACCES; + ntfs_log_trace("Cannot truncate encrypted attribute\n"); + goto out; + } + /* + * TODO: Implement making handling of compressed attributes. + * Currently we can only expand the attribute or delete it, + * and only for ATTR_IS_COMPRESSED. This is however possible + * for resident attributes when there is no open fuse context + * (important case : $INDEX_ROOT:$I30) + */ + compressed = (na->data_flags & ATTR_COMPRESSION_MASK) + != const_cpu_to_le16(0); + if (compressed + && NAttrNonResident(na) + && (((na->data_flags & ATTR_COMPRESSION_MASK) != ATTR_IS_COMPRESSED) + || (newsize && (newsize < na->data_size)))) { + errno = EOPNOTSUPP; + ntfs_log_perror("Failed to truncate compressed attribute"); + goto out; + } + if (NAttrNonResident(na)) { + /* + * For compressed data, the last block must be fully + * allocated, and we do not known the size of compression + * block until the attribute has been made non-resident. + * Moreover we can only process a single compression + * block at a time (from where we are about to write), + * so we silently do not allocate more. + * + * Note : do not request truncate on compressed files + * unless being able to face the consequences ! + */ + if (compressed && newsize) + fullsize = (na->initialized_size + | (na->compression_block_size - 1)) + 1; + else + fullsize = newsize; + if (fullsize > na->data_size) + ret = ntfs_non_resident_attr_expand(na, fullsize); + else + ret = ntfs_non_resident_attr_shrink(na, fullsize); + } else + ret = ntfs_resident_attr_resize(na, newsize); +out: + ntfs_log_leave("Return status %d\n", ret); + return ret; +} + +/* + * Stuff a hole in a compressed file + * + * An unallocated hole must be aligned on compression block size. + * If needed current block and target block are stuffed with zeroes. + * + * Returns 0 if succeeded, + * -1 if it failed (as explained in errno) + */ + +static int stuff_hole(ntfs_attr *na, const s64 pos) +{ + s64 size; + s64 begin_size; + s64 end_size; + char *buf; + int ret; + + ret = 0; + /* + * If the attribute is resident, the compression block size + * is not defined yet and we can make no decision. + * So we first try resizing to the target and if the + * attribute is still resident, we're done + */ + if (!NAttrNonResident(na)) { + ret = ntfs_resident_attr_resize(na, pos); + if (!ret && !NAttrNonResident(na)) + na->initialized_size = na->data_size = pos; + } + if (!ret && NAttrNonResident(na)) { + /* does the hole span over several compression block ? */ + if ((pos ^ na->initialized_size) + & ~(na->compression_block_size - 1)) { + begin_size = ((na->initialized_size - 1) + | (na->compression_block_size - 1)) + + 1 - na->initialized_size; + end_size = pos & (na->compression_block_size - 1); + size = (begin_size > end_size ? begin_size : end_size); + } else { + /* short stuffing in a single compression block */ + begin_size = size = pos - na->initialized_size; + end_size = 0; + } + if (size) + buf = (char*)ntfs_malloc(size); + else + buf = (char*)NULL; + if (buf || !size) { + memset(buf,0,size); + /* stuff into current block */ + if (begin_size + && (ntfs_attr_pwrite(na, + na->initialized_size, begin_size, buf) + != begin_size)) + ret = -1; + /* create an unstuffed hole */ + if (!ret + && ((na->initialized_size + end_size) < pos) + && ntfs_non_resident_attr_expand(na, + pos - end_size)) + ret = -1; + else + na->initialized_size + = na->data_size = pos - end_size; + /* stuff into the target block */ + if (!ret && end_size + && (ntfs_attr_pwrite(na, + na->initialized_size, end_size, buf) + != end_size)) + ret = -1; + if (buf) + free(buf); + } else + ret = -1; + } + /* make absolutely sure we have reached the target */ + if (!ret && (na->initialized_size != pos)) { + ntfs_log_error("Failed to stuff a compressed file" + "target %lld reached %lld\n", + (long long)pos, (long long)na->initialized_size); + errno = EIO; + ret = -1; + } + return (ret); +} + +/** + * ntfs_attr_readall - read the entire data from an ntfs attribute + * @ni: open ntfs inode in which the ntfs attribute resides + * @type: attribute type + * @name: attribute name in little endian Unicode or AT_UNNAMED or NULL + * @name_len: length of attribute @name in Unicode characters (if @name given) + * @data_size: if non-NULL then store here the data size + * + * This function will read the entire content of an ntfs attribute. + * If @name is AT_UNNAMED then look specifically for an unnamed attribute. + * If @name is NULL then the attribute could be either named or not. + * In both those cases @name_len is not used at all. + * + * On success a buffer is allocated with the content of the attribute + * and which needs to be freed when it's not needed anymore. If the + * @data_size parameter is non-NULL then the data size is set there. + * + * On error NULL is returned with errno set to the error code. + */ +void *ntfs_attr_readall(ntfs_inode *ni, const ATTR_TYPES type, + ntfschar *name, u32 name_len, s64 *data_size) +{ + ntfs_attr *na; + void *data, *ret = NULL; + s64 size; + + ntfs_log_enter("Entering\n"); + + na = ntfs_attr_open(ni, type, name, name_len); + if (!na) { + ntfs_log_perror("ntfs_attr_open failed"); + goto err_exit; + } + data = ntfs_malloc(na->data_size); + if (!data) + goto out; + + size = ntfs_attr_pread(na, 0, na->data_size, data); + if (size != na->data_size) { + ntfs_log_perror("ntfs_attr_pread failed"); + free(data); + goto out; + } + ret = data; + if (data_size) + *data_size = size; +out: + ntfs_attr_close(na); +err_exit: + ntfs_log_leave("\n"); + return ret; +} + + + +int ntfs_attr_exist(ntfs_inode *ni, const ATTR_TYPES type, ntfschar *name, + u32 name_len) +{ + ntfs_attr_search_ctx *ctx; + int ret; + + ntfs_log_trace("Entering\n"); + + ctx = ntfs_attr_get_search_ctx(ni, NULL); + if (!ctx) + return 0; + + ret = ntfs_attr_lookup(type, name, name_len, CASE_SENSITIVE, 0, NULL, 0, + ctx); + + ntfs_attr_put_search_ctx(ctx); + + return !ret; +} + +int ntfs_attr_remove(ntfs_inode *ni, const ATTR_TYPES type, ntfschar *name, + u32 name_len) +{ + ntfs_attr *na; + int ret; + + ntfs_log_trace("Entering\n"); + + if (!ni) { + ntfs_log_error("%s: NULL inode pointer", __FUNCTION__); + errno = EINVAL; + return -1; + } + + na = ntfs_attr_open(ni, type, name, name_len); + if (!na) { + /* do not log removal of non-existent stream */ + if (type != AT_DATA) { + ntfs_log_perror("Failed to open attribute 0x%02x of inode " + "0x%llx", type, (unsigned long long)ni->mft_no); + } + return -1; + } + + ret = ntfs_attr_rm(na); + if (ret) + ntfs_log_perror("Failed to remove attribute 0x%02x of inode " + "0x%llx", type, (unsigned long long)ni->mft_no); + ntfs_attr_close(na); + + return ret; +} + +/* Below macros are 32-bit ready. */ +#define BCX(x) ((x) - (((x) >> 1) & 0x77777777) - \ + (((x) >> 2) & 0x33333333) - \ + (((x) >> 3) & 0x11111111)) +#define BITCOUNT(x) (((BCX(x) + (BCX(x) >> 4)) & 0x0F0F0F0F) % 255) + +static u8 *ntfs_init_lut256(void) +{ + int i; + u8 *lut; + + lut = ntfs_malloc(256); + if (lut) + for(i = 0; i < 256; i++) + *(lut + i) = 8 - BITCOUNT(i); + return lut; +} + +s64 ntfs_attr_get_free_bits(ntfs_attr *na) +{ + u8 *buf, *lut; + s64 br = 0; + s64 total = 0; + s64 nr_free = 0; + + lut = ntfs_init_lut256(); + if (!lut) + return -1; + + buf = ntfs_malloc(65536); + if (!buf) + goto out; + + while (1) { + u32 *p; + br = ntfs_attr_pread(na, total, 65536, buf); + if (br <= 0) + break; + total += br; + p = (u32 *)buf + br / 4 - 1; + for (; (u8 *)p >= buf; p--) { + nr_free += lut[ *p & 255] + + lut[(*p >> 8) & 255] + + lut[(*p >> 16) & 255] + + lut[(*p >> 24) ]; + } + switch (br % 4) { + case 3: nr_free += lut[*(buf + br - 3)]; + case 2: nr_free += lut[*(buf + br - 2)]; + case 1: nr_free += lut[*(buf + br - 1)]; + } + } + free(buf); +out: + free(lut); + if (!total || br < 0) + return -1; + return nr_free; +} diff --git a/libntfs-3g/attrlist.c b/libntfs-3g/attrlist.c new file mode 100755 index 0000000..9c62f31 --- a/dev/null +++ b/libntfs-3g/attrlist.c @@ -0,0 +1,314 @@ +/** + * attrlist.c - Attribute list attribute handling code. Originated from the Linux-NTFS + * project. + * + * Copyright (c) 2004-2005 Anton Altaparmakov + * Copyright (c) 2004-2005 Yura Pakhuchiy + * Copyright (c) 2006 Szabolcs Szakacsits + * + * This program/include file 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/include file 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 (in the main directory of the NTFS-3G + * distribution in the file COPYING); if not, write to the Free Software + * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_ERRNO_H +#include +#endif + +#include "types.h" +#include "layout.h" +#include "attrib.h" +#include "attrlist.h" +#include "debug.h" +#include "unistr.h" +#include "logging.h" +#include "misc.h" + +/** + * ntfs_attrlist_need - check whether inode need attribute list + * @ni: opened ntfs inode for which perform check + * + * Check whether all are attributes belong to one MFT record, in that case + * attribute list is not needed. + * + * Return 1 if inode need attribute list, 0 if not, -1 on error with errno set + * to the error code. If function succeed errno set to 0. The following error + * codes are defined: + * EINVAL - Invalid arguments passed to function or attribute haven't got + * attribute list. + */ +int ntfs_attrlist_need(ntfs_inode *ni) +{ + ATTR_LIST_ENTRY *ale; + + if (!ni) { + ntfs_log_trace("Invalid arguments.\n"); + errno = EINVAL; + return -1; + } + + ntfs_log_trace("Entering for inode 0x%llx.\n", (long long) ni->mft_no); + + if (!NInoAttrList(ni)) { + ntfs_log_trace("Inode haven't got attribute list.\n"); + errno = EINVAL; + return -1; + } + + if (!ni->attr_list) { + ntfs_log_trace("Corrupt in-memory struct.\n"); + errno = EINVAL; + return -1; + } + + errno = 0; + ale = (ATTR_LIST_ENTRY *)ni->attr_list; + while ((u8*)ale < ni->attr_list + ni->attr_list_size) { + if (MREF_LE(ale->mft_reference) != ni->mft_no) + return 1; + ale = (ATTR_LIST_ENTRY *)((u8*)ale + le16_to_cpu(ale->length)); + } + return 0; +} + +/** + * ntfs_attrlist_entry_add - add an attribute list attribute entry + * @ni: opened ntfs inode, which contains that attribute + * @attr: attribute record to add to attribute list + * + * Return 0 on success and -1 on error with errno set to the error code. The + * following error codes are defined: + * EINVAL - Invalid arguments passed to function. + * ENOMEM - Not enough memory to allocate necessary buffers. + * EIO - I/O error occurred or damaged filesystem. + * EEXIST - Such attribute already present in attribute list. + */ +int ntfs_attrlist_entry_add(ntfs_inode *ni, ATTR_RECORD *attr) +{ + ATTR_LIST_ENTRY *ale; + MFT_REF mref; + ntfs_attr *na = NULL; + ntfs_attr_search_ctx *ctx; + u8 *new_al; + int entry_len, entry_offset, err; + + ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x.\n", + (long long) ni->mft_no, + (unsigned) le32_to_cpu(attr->type)); + + if (!ni || !attr) { + ntfs_log_trace("Invalid arguments.\n"); + errno = EINVAL; + return -1; + } + + mref = MK_LE_MREF(ni->mft_no, le16_to_cpu(ni->mrec->sequence_number)); + + if (ni->nr_extents == -1) + ni = ni->base_ni; + + if (!NInoAttrList(ni)) { + ntfs_log_trace("Attribute list isn't present.\n"); + errno = ENOENT; + return -1; + } + + /* Determine size and allocate memory for new attribute list. */ + entry_len = (sizeof(ATTR_LIST_ENTRY) + sizeof(ntfschar) * + attr->name_length + 7) & ~7; + new_al = ntfs_calloc(ni->attr_list_size + entry_len); + if (!new_al) + return -1; + + /* Find place for the new entry. */ + ctx = ntfs_attr_get_search_ctx(ni, NULL); + if (!ctx) { + err = errno; + goto err_out; + } + if (!ntfs_attr_lookup(attr->type, (attr->name_length) ? (ntfschar*) + ((u8*)attr + le16_to_cpu(attr->name_offset)) : + AT_UNNAMED, attr->name_length, CASE_SENSITIVE, + (attr->non_resident) ? le64_to_cpu(attr->lowest_vcn) : + 0, (attr->non_resident) ? NULL : ((u8*)attr + + le16_to_cpu(attr->value_offset)), (attr->non_resident) ? + 0 : le32_to_cpu(attr->value_length), ctx)) { + /* Found some extent, check it to be before new extent. */ + if (ctx->al_entry->lowest_vcn == attr->lowest_vcn) { + err = EEXIST; + ntfs_log_trace("Such attribute already present in the " + "attribute list.\n"); + ntfs_attr_put_search_ctx(ctx); + goto err_out; + } + /* Add new entry after this extent. */ + ale = (ATTR_LIST_ENTRY*)((u8*)ctx->al_entry + + le16_to_cpu(ctx->al_entry->length)); + } else { + /* Check for real errors. */ + if (errno != ENOENT) { + err = errno; + ntfs_log_trace("Attribute lookup failed.\n"); + ntfs_attr_put_search_ctx(ctx); + goto err_out; + } + /* No previous extents found. */ + ale = ctx->al_entry; + } + /* Don't need it anymore, @ctx->al_entry points to @ni->attr_list. */ + ntfs_attr_put_search_ctx(ctx); + + /* Determine new entry offset. */ + entry_offset = ((u8 *)ale - ni->attr_list); + /* Set pointer to new entry. */ + ale = (ATTR_LIST_ENTRY *)(new_al + entry_offset); + /* Zero it to fix valgrind warning. */ + memset(ale, 0, entry_len); + /* Form new entry. */ + ale->type = attr->type; + ale->length = cpu_to_le16(entry_len); + ale->name_length = attr->name_length; + ale->name_offset = offsetof(ATTR_LIST_ENTRY, name); + if (attr->non_resident) + ale->lowest_vcn = attr->lowest_vcn; + else + ale->lowest_vcn = 0; + ale->mft_reference = mref; + ale->instance = attr->instance; + memcpy(ale->name, (u8 *)attr + le16_to_cpu(attr->name_offset), + attr->name_length * sizeof(ntfschar)); + + /* Resize $ATTRIBUTE_LIST to new length. */ + na = ntfs_attr_open(ni, AT_ATTRIBUTE_LIST, AT_UNNAMED, 0); + if (!na) { + err = errno; + ntfs_log_trace("Failed to open $ATTRIBUTE_LIST attribute.\n"); + goto err_out; + } + if (ntfs_attr_truncate(na, ni->attr_list_size + entry_len)) { + err = errno; + ntfs_log_trace("$ATTRIBUTE_LIST resize failed.\n"); + goto err_out; + } + + /* Copy entries from old attribute list to new. */ + memcpy(new_al, ni->attr_list, entry_offset); + memcpy(new_al + entry_offset + entry_len, ni->attr_list + + entry_offset, ni->attr_list_size - entry_offset); + + /* Set new runlist. */ + free(ni->attr_list); + ni->attr_list = new_al; + ni->attr_list_size = ni->attr_list_size + entry_len; + NInoAttrListSetDirty(ni); + /* Done! */ + ntfs_attr_close(na); + return 0; +err_out: + if (na) + ntfs_attr_close(na); + free(new_al); + errno = err; + return -1; +} + +/** + * ntfs_attrlist_entry_rm - remove an attribute list attribute entry + * @ctx: attribute search context describing the attribute list entry + * + * Remove the attribute list entry @ctx->al_entry from the attribute list. + * + * Return 0 on success and -1 on error with errno set to the error code. + */ +int ntfs_attrlist_entry_rm(ntfs_attr_search_ctx *ctx) +{ + u8 *new_al; + int new_al_len; + ntfs_inode *base_ni; + ntfs_attr *na; + ATTR_LIST_ENTRY *ale; + int err; + + if (!ctx || !ctx->ntfs_ino || !ctx->al_entry) { + ntfs_log_trace("Invalid arguments.\n"); + errno = EINVAL; + return -1; + } + + if (ctx->base_ntfs_ino) + base_ni = ctx->base_ntfs_ino; + else + base_ni = ctx->ntfs_ino; + ale = ctx->al_entry; + + ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x, lowest_vcn %lld.\n", + (long long) ctx->ntfs_ino->mft_no, + (unsigned) le32_to_cpu(ctx->al_entry->type), + (long long) le64_to_cpu(ctx->al_entry->lowest_vcn)); + + if (!NInoAttrList(base_ni)) { + ntfs_log_trace("Attribute list isn't present.\n"); + errno = ENOENT; + return -1; + } + + /* Allocate memory for new attribute list. */ + new_al_len = base_ni->attr_list_size - le16_to_cpu(ale->length); + new_al = ntfs_calloc(new_al_len); + if (!new_al) + return -1; + + /* Reisze $ATTRIBUTE_LIST to new length. */ + na = ntfs_attr_open(base_ni, AT_ATTRIBUTE_LIST, AT_UNNAMED, 0); + if (!na) { + err = errno; + ntfs_log_trace("Failed to open $ATTRIBUTE_LIST attribute.\n"); + goto err_out; + } + if (ntfs_attr_truncate(na, new_al_len)) { + err = errno; + ntfs_log_trace("$ATTRIBUTE_LIST resize failed.\n"); + goto err_out; + } + + /* Copy entries from old attribute list to new. */ + memcpy(new_al, base_ni->attr_list, (u8*)ale - base_ni->attr_list); + memcpy(new_al + ((u8*)ale - base_ni->attr_list), (u8*)ale + le16_to_cpu( + ale->length), new_al_len - ((u8*)ale - base_ni->attr_list)); + + /* Set new runlist. */ + free(base_ni->attr_list); + base_ni->attr_list = new_al; + base_ni->attr_list_size = new_al_len; + NInoAttrListSetDirty(base_ni); + /* Done! */ + ntfs_attr_close(na); + return 0; +err_out: + if (na) + ntfs_attr_close(na); + free(new_al); + errno = err; + return -1; +} diff --git a/libntfs-3g/bitmap.c b/libntfs-3g/bitmap.c new file mode 100755 index 0000000..65162a2 --- a/dev/null +++ b/libntfs-3g/bitmap.c @@ -0,0 +1,300 @@ +/** + * bitmap.c - Bitmap handling code. Originated from the Linux-NTFS project. + * + * Copyright (c) 2002-2006 Anton Altaparmakov + * Copyright (c) 2004-2005 Richard Russon + * Copyright (c) 2004-2008 Szabolcs Szakacsits + * + * This program/include file 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/include file 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 (in the main directory of the NTFS-3G + * distribution in the file COPYING); if not, write to the Free Software + * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STDIO_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_ERRNO_H +#include +#endif + +#include "types.h" +#include "attrib.h" +#include "bitmap.h" +#include "debug.h" +#include "logging.h" +#include "misc.h" + +/** + * ntfs_bit_set - set a bit in a field of bits + * @bitmap: field of bits + * @bit: bit to set + * @new_value: value to set bit to (0 or 1) + * + * Set the bit @bit in the @bitmap to @new_value. Ignore all errors. + */ +void ntfs_bit_set(u8 *bitmap, const u64 bit, const u8 new_value) +{ + if (!bitmap || new_value > 1) + return; + if (!new_value) + bitmap[bit >> 3] &= ~(1 << (bit & 7)); + else + bitmap[bit >> 3] |= (1 << (bit & 7)); +} + +/** + * ntfs_bit_get - get value of a bit in a field of bits + * @bitmap: field of bits + * @bit: bit to get + * + * Get and return the value of the bit @bit in @bitmap (0 or 1). + * Return -1 on error. + */ +char ntfs_bit_get(const u8 *bitmap, const u64 bit) +{ + if (!bitmap) + return -1; + return (bitmap[bit >> 3] >> (bit & 7)) & 1; +} + +/** + * ntfs_bit_get_and_set - get value of a bit in a field of bits and set it + * @bitmap: field of bits + * @bit: bit to get/set + * @new_value: value to set bit to (0 or 1) + * + * Return the value of the bit @bit and set it to @new_value (0 or 1). + * Return -1 on error. + */ +char ntfs_bit_get_and_set(u8 *bitmap, const u64 bit, const u8 new_value) +{ + register u8 old_bit, shift; + + if (!bitmap || new_value > 1) + return -1; + shift = bit & 7; + old_bit = (bitmap[bit >> 3] >> shift) & 1; + if (new_value != old_bit) + bitmap[bit >> 3] ^= 1 << shift; + return old_bit; +} + +/** + * ntfs_bitmap_set_bits_in_run - set a run of bits in a bitmap to a value + * @na: attribute containing the bitmap + * @start_bit: first bit to set + * @count: number of bits to set + * @value: value to set the bits to (i.e. 0 or 1) + * + * Set @count bits starting at bit @start_bit in the bitmap described by the + * attribute @na to @value, where @value is either 0 or 1. + * + * On success return 0 and on error return -1 with errno set to the error code. + */ +static int ntfs_bitmap_set_bits_in_run(ntfs_attr *na, s64 start_bit, + s64 count, int value) +{ + s64 bufsize, br; + u8 *buf, *lastbyte_buf; + int bit, firstbyte, lastbyte, lastbyte_pos, tmp, ret = -1; + + if (!na || start_bit < 0 || count < 0) { + errno = EINVAL; + ntfs_log_perror("%s: Invalid argument (%p, %lld, %lld)", + __FUNCTION__, na, (long long)start_bit, (long long)count); + return -1; + } + + bit = start_bit & 7; + if (bit) + firstbyte = 1; + else + firstbyte = 0; + + /* Calculate the required buffer size in bytes, capping it at 8kiB. */ + bufsize = ((count - (bit ? 8 - bit : 0) + 7) >> 3) + firstbyte; + if (bufsize > 8192) + bufsize = 8192; + + buf = ntfs_malloc(bufsize); + if (!buf) + return -1; + + /* Depending on @value, zero or set all bits in the allocated buffer. */ + memset(buf, value ? 0xff : 0, bufsize); + + /* If there is a first partial byte... */ + if (bit) { + /* read it in... */ + br = ntfs_attr_pread(na, start_bit >> 3, 1, buf); + if (br != 1) { + if (br >= 0) + errno = EIO; + goto free_err_out; + } + /* and set or clear the appropriate bits in it. */ + while ((bit & 7) && count--) { + if (value) + *buf |= 1 << bit++; + else + *buf &= ~(1 << bit++); + } + /* Update @start_bit to the new position. */ + start_bit = (start_bit + 7) & ~7; + } + + /* Loop until @count reaches zero. */ + lastbyte = 0; + lastbyte_buf = NULL; + bit = count & 7; + do { + /* If there is a last partial byte... */ + if (count > 0 && bit) { + lastbyte_pos = ((count + 7) >> 3) + firstbyte; + if (!lastbyte_pos) { + // FIXME: Eeek! BUG! + ntfs_log_error("Lastbyte is zero. Leaving " + "inconsistent metadata.\n"); + errno = EIO; + goto free_err_out; + } + /* and it is in the currently loaded bitmap window... */ + if (lastbyte_pos <= bufsize) { + lastbyte_buf = buf + lastbyte_pos - 1; + + /* read the byte in... */ + br = ntfs_attr_pread(na, (start_bit + count) >> + 3, 1, lastbyte_buf); + if (br != 1) { + // FIXME: Eeek! We need rollback! (AIA) + if (br >= 0) + errno = EIO; + ntfs_log_perror("Reading of last byte " + "failed (%lld). Leaving inconsistent " + "metadata", (long long)br); + goto free_err_out; + } + /* and set/clear the appropriate bits in it. */ + while (bit && count--) { + if (value) + *lastbyte_buf |= 1 << --bit; + else + *lastbyte_buf &= ~(1 << --bit); + } + /* We don't want to come back here... */ + bit = 0; + /* We have a last byte that we have handled. */ + lastbyte = 1; + } + } + + /* Write the prepared buffer to disk. */ + tmp = (start_bit >> 3) - firstbyte; + br = ntfs_attr_pwrite(na, tmp, bufsize, buf); + if (br != bufsize) { + // FIXME: Eeek! We need rollback! (AIA) + if (br >= 0) + errno = EIO; + ntfs_log_perror("Failed to write buffer to bitmap " + "(%lld != %lld). Leaving inconsistent metadata", + (long long)br, (long long)bufsize); + goto free_err_out; + } + + /* Update counters. */ + tmp = (bufsize - firstbyte - lastbyte) << 3; + if (firstbyte) { + firstbyte = 0; + /* + * Re-set the partial first byte so a subsequent write + * of the buffer does not have stale, incorrect bits. + */ + *buf = value ? 0xff : 0; + } + start_bit += tmp; + count -= tmp; + if (bufsize > (tmp = (count + 7) >> 3)) + bufsize = tmp; + + if (lastbyte && count != 0) { + // FIXME: Eeek! BUG! + ntfs_log_error("Last buffer but count is not zero " + "(%lld). Leaving inconsistent metadata.\n", + (long long)count); + errno = EIO; + goto free_err_out; + } + } while (count > 0); + + ret = 0; + +free_err_out: + free(buf); + return ret; +} + +/** + * ntfs_bitmap_set_run - set a run of bits in a bitmap + * @na: attribute containing the bitmap + * @start_bit: first bit to set + * @count: number of bits to set + * + * Set @count bits starting at bit @start_bit in the bitmap described by the + * attribute @na. + * + * On success return 0 and on error return -1 with errno set to the error code. + */ +int ntfs_bitmap_set_run(ntfs_attr *na, s64 start_bit, s64 count) +{ + int ret; + + ntfs_log_enter("Set from bit %lld, count %lld\n", + (long long)start_bit, (long long)count); + ret = ntfs_bitmap_set_bits_in_run(na, start_bit, count, 1); + ntfs_log_leave("\n"); + return ret; +} + +/** + * ntfs_bitmap_clear_run - clear a run of bits in a bitmap + * @na: attribute containing the bitmap + * @start_bit: first bit to clear + * @count: number of bits to clear + * + * Clear @count bits starting at bit @start_bit in the bitmap described by the + * attribute @na. + * + * On success return 0 and on error return -1 with errno set to the error code. + */ +int ntfs_bitmap_clear_run(ntfs_attr *na, s64 start_bit, s64 count) +{ + int ret; + + ntfs_log_enter("Clear from bit %lld, count %lld\n", + (long long)start_bit, (long long)count); + ret = ntfs_bitmap_set_bits_in_run(na, start_bit, count, 0); + ntfs_log_leave("\n"); + return ret; +} + diff --git a/libntfs-3g/bootsect.c b/libntfs-3g/bootsect.c new file mode 100755 index 0000000..e9bea37 --- a/dev/null +++ b/libntfs-3g/bootsect.c @@ -0,0 +1,285 @@ +/** + * bootsect.c - Boot sector handling code. Originated from the Linux-NTFS project. + * + * Copyright (c) 2000-2006 Anton Altaparmakov + * Copyright (c) 2003-2008 Szabolcs Szakacsits + * Copyright (c) 2005 Yura Pakhuchiy + * + * This program/include file 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/include file 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 (in the main directory of the NTFS-3G + * distribution in the file COPYING); if not, write to the Free Software + * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_STDIO_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_ERRNO_H +#include +#endif + +#include "compat.h" +#include "bootsect.h" +#include "debug.h" +#include "logging.h" + +/** + * ntfs_boot_sector_is_ntfs - check if buffer contains a valid ntfs boot sector + * @b: buffer containing putative boot sector to analyze + * @silent: if zero, output progress messages to stderr + * + * Check if the buffer @b contains a valid ntfs boot sector. The buffer @b + * must be at least 512 bytes in size. + * + * If @silent is zero, output progress messages to stderr. Otherwise, do not + * output any messages (except when configured with --enable-debug in which + * case warning/debug messages may be displayed). + * + * Return TRUE if @b contains a valid ntfs boot sector and FALSE if not. + */ +BOOL ntfs_boot_sector_is_ntfs(NTFS_BOOT_SECTOR *b) +{ + u32 i; + BOOL ret = FALSE; + + ntfs_log_debug("Beginning bootsector check.\n"); + + ntfs_log_debug("Checking OEMid, NTFS signature.\n"); + if (b->oem_id != cpu_to_le64(0x202020205346544eULL)) { /* "NTFS " */ + ntfs_log_error("NTFS signature is missing.\n"); + goto not_ntfs; + } + + ntfs_log_debug("Checking bytes per sector.\n"); + if (le16_to_cpu(b->bpb.bytes_per_sector) < 256 || + le16_to_cpu(b->bpb.bytes_per_sector) > 4096) { + ntfs_log_error("Unexpected bytes per sector value (%d).\n", + le16_to_cpu(b->bpb.bytes_per_sector)); + goto not_ntfs; + } + + ntfs_log_debug("Checking sectors per cluster.\n"); + switch (b->bpb.sectors_per_cluster) { + case 1: case 2: case 4: case 8: case 16: case 32: case 64: case 128: + break; + default: + ntfs_log_error("Unexpected sectors per cluster value (%d).\n", + b->bpb.sectors_per_cluster); + goto not_ntfs; + } + + ntfs_log_debug("Checking cluster size.\n"); + i = (u32)le16_to_cpu(b->bpb.bytes_per_sector) * + b->bpb.sectors_per_cluster; + if (i > 65536) { + ntfs_log_error("Unexpected cluster size (%d).\n", i); + goto not_ntfs; + } + + ntfs_log_debug("Checking reserved fields are zero.\n"); + if (le16_to_cpu(b->bpb.reserved_sectors) || + le16_to_cpu(b->bpb.root_entries) || + le16_to_cpu(b->bpb.sectors) || + le16_to_cpu(b->bpb.sectors_per_fat) || + le32_to_cpu(b->bpb.large_sectors) || + b->bpb.fats) { + ntfs_log_error("Reserved fields aren't zero " + "(%d, %d, %d, %d, %d, %d).\n", + le16_to_cpu(b->bpb.reserved_sectors), + le16_to_cpu(b->bpb.root_entries), + le16_to_cpu(b->bpb.sectors), + le16_to_cpu(b->bpb.sectors_per_fat), + le32_to_cpu(b->bpb.large_sectors), + b->bpb.fats); + goto not_ntfs; + } + + ntfs_log_debug("Checking clusters per mft record.\n"); + if ((u8)b->clusters_per_mft_record < 0xe1 || + (u8)b->clusters_per_mft_record > 0xf7) { + switch (b->clusters_per_mft_record) { + case 1: case 2: case 4: case 8: case 0x10: case 0x20: case 0x40: + break; + default: + ntfs_log_error("Unexpected clusters per mft record " + "(%d).\n", b->clusters_per_mft_record); + goto not_ntfs; + } + } + + ntfs_log_debug("Checking clusters per index block.\n"); + if ((u8)b->clusters_per_index_record < 0xe1 || + (u8)b->clusters_per_index_record > 0xf7) { + switch (b->clusters_per_index_record) { + case 1: case 2: case 4: case 8: case 0x10: case 0x20: case 0x40: + break; + default: + ntfs_log_error("Unexpected clusters per index record " + "(%d).\n", b->clusters_per_index_record); + goto not_ntfs; + } + } + + if (b->end_of_sector_marker != cpu_to_le16(0xaa55)) + ntfs_log_debug("Warning: Bootsector has invalid end of sector " + "marker.\n"); + + ntfs_log_debug("Bootsector check completed successfully.\n"); + + ret = TRUE; +not_ntfs: + return ret; +} + +static const char *last_sector_error = +"HINTS: Either the volume is a RAID/LDM but it wasn't setup yet,\n" +" or it was not setup correctly (e.g. by not using mdadm --build ...),\n" +" or a wrong device is tried to be mounted,\n" +" or the partition table is corrupt (partition is smaller than NTFS),\n" +" or the NTFS boot sector is corrupt (NTFS size is not valid).\n"; + +/** + * ntfs_boot_sector_parse - setup an ntfs volume from an ntfs boot sector + * @vol: ntfs_volume to setup + * @bs: buffer containing ntfs boot sector to parse + * + * Parse the ntfs bootsector @bs and setup the ntfs volume @vol with the + * obtained values. + * + * Return 0 on success or -1 on error with errno set to the error code EINVAL. + */ +int ntfs_boot_sector_parse(ntfs_volume *vol, const NTFS_BOOT_SECTOR *bs) +{ + s64 sectors; + u8 sectors_per_cluster; + s8 c; + + /* We return -1 with errno = EINVAL on error. */ + errno = EINVAL; + + vol->sector_size = le16_to_cpu(bs->bpb.bytes_per_sector); + vol->sector_size_bits = ffs(vol->sector_size) - 1; + ntfs_log_debug("SectorSize = 0x%x\n", vol->sector_size); + ntfs_log_debug("SectorSizeBits = %u\n", vol->sector_size_bits); + /* + * The bounds checks on mft_lcn and mft_mirr_lcn (i.e. them being + * below or equal the number_of_clusters) really belong in the + * ntfs_boot_sector_is_ntfs but in this way we can just do this once. + */ + sectors_per_cluster = bs->bpb.sectors_per_cluster; + ntfs_log_debug("SectorsPerCluster = 0x%x\n", sectors_per_cluster); + if (sectors_per_cluster & (sectors_per_cluster - 1)) { + ntfs_log_error("sectors_per_cluster (%d) is not a power of 2." + "\n", sectors_per_cluster); + return -1; + } + + sectors = sle64_to_cpu(bs->number_of_sectors); + ntfs_log_debug("NumberOfSectors = %lld\n", (long long)sectors); + if (!sectors) { + ntfs_log_error("Volume size is set to zero.\n"); + return -1; + } + if (vol->dev->d_ops->seek(vol->dev, + (sectors - 1) << vol->sector_size_bits, + SEEK_SET) == -1) { + ntfs_log_perror("Failed to read last sector (%lld)", + (long long)sectors); + ntfs_log_error("%s", last_sector_error); + return -1; + } + + vol->nr_clusters = sectors >> (ffs(sectors_per_cluster) - 1); + + vol->mft_lcn = sle64_to_cpu(bs->mft_lcn); + vol->mftmirr_lcn = sle64_to_cpu(bs->mftmirr_lcn); + ntfs_log_debug("MFT LCN = %lld\n", (long long)vol->mft_lcn); + ntfs_log_debug("MFTMirr LCN = %lld\n", (long long)vol->mftmirr_lcn); + if (vol->mft_lcn > vol->nr_clusters || + vol->mftmirr_lcn > vol->nr_clusters) { + ntfs_log_error("$MFT LCN (%lld) or $MFTMirr LCN (%lld) is " + "greater than the number of clusters (%lld).\n", + (long long)vol->mft_lcn, (long long)vol->mftmirr_lcn, + (long long)vol->nr_clusters); + return -1; + } + + vol->cluster_size = sectors_per_cluster * vol->sector_size; + if (vol->cluster_size & (vol->cluster_size - 1)) { + ntfs_log_error("cluster_size (%d) is not a power of 2.\n", + vol->cluster_size); + return -1; + } + vol->cluster_size_bits = ffs(vol->cluster_size) - 1; + /* + * Need to get the clusters per mft record and handle it if it is + * negative. Then calculate the mft_record_size. A value of 0x80 is + * illegal, thus signed char is actually ok! + */ + c = bs->clusters_per_mft_record; + ntfs_log_debug("ClusterSize = 0x%x\n", (unsigned)vol->cluster_size); + ntfs_log_debug("ClusterSizeBits = %u\n", vol->cluster_size_bits); + ntfs_log_debug("ClustersPerMftRecord = 0x%x\n", c); + /* + * When clusters_per_mft_record is negative, it means that it is to + * be taken to be the negative base 2 logarithm of the mft_record_size + * min bytes. Then: + * mft_record_size = 2^(-clusters_per_mft_record) bytes. + */ + if (c < 0) + vol->mft_record_size = 1 << -c; + else + vol->mft_record_size = c << vol->cluster_size_bits; + if (vol->mft_record_size & (vol->mft_record_size - 1)) { + ntfs_log_error("mft_record_size (%d) is not a power of 2.\n", + vol->mft_record_size); + return -1; + } + vol->mft_record_size_bits = ffs(vol->mft_record_size) - 1; + ntfs_log_debug("MftRecordSize = 0x%x\n", (unsigned)vol->mft_record_size); + ntfs_log_debug("MftRecordSizeBits = %u\n", vol->mft_record_size_bits); + /* Same as above for INDX record. */ + c = bs->clusters_per_index_record; + ntfs_log_debug("ClustersPerINDXRecord = 0x%x\n", c); + if (c < 0) + vol->indx_record_size = 1 << -c; + else + vol->indx_record_size = c << vol->cluster_size_bits; + vol->indx_record_size_bits = ffs(vol->indx_record_size) - 1; + ntfs_log_debug("INDXRecordSize = 0x%x\n", (unsigned)vol->indx_record_size); + ntfs_log_debug("INDXRecordSizeBits = %u\n", vol->indx_record_size_bits); + /* + * Work out the size of the MFT mirror in number of mft records. If the + * cluster size is less than or equal to the size taken by four mft + * records, the mft mirror stores the first four mft records. If the + * cluster size is bigger than the size taken by four mft records, the + * mft mirror contains as many mft records as will fit into one + * cluster. + */ + if (vol->cluster_size <= 4 * vol->mft_record_size) + vol->mftmirr_size = 4; + else + vol->mftmirr_size = vol->cluster_size / vol->mft_record_size; + return 0; +} + diff --git a/libntfs-3g/cache.c b/libntfs-3g/cache.c new file mode 100755 index 0000000..dd14767 --- a/dev/null +++ b/libntfs-3g/cache.c @@ -0,0 +1,609 @@ +/** + * cache.c : deal with LRU caches + * + * Copyright (c) 2008-2009 Jean-Pierre Andre + * + * This program/include file 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/include file 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 (in the main directory of the NTFS-3G + * distribution in the file COPYING); if not, write to the Free Software + * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif + +#include "types.h" +#include "security.h" +#include "cache.h" +#include "misc.h" +#include "logging.h" + +/* + * General functions to deal with LRU caches + * + * The cached data have to be organized in a structure in which + * the first fields must follow a mandatory pattern and further + * fields may contain any fixed size data. They are stored in an + * LRU list. + * + * A compare function must be provided for finding a wanted entry + * in the cache. Another function may be provided for invalidating + * an entry to facilitate multiple invalidation. + * + * These functions never return error codes. When there is a + * shortage of memory, data is simply not cached. + * When there is a hashing bug, hashing is dropped, and sequential + * searches are used. + */ + +/* + * Enter a new hash index, after a new record has been inserted + * + * Do not call when a record has been modified (with no key change) + */ + +static void inserthashindex(struct CACHE_HEADER *cache, + struct CACHED_GENERIC *current) +{ + int h; + struct HASH_ENTRY *link; + struct HASH_ENTRY *first; + + if (cache->dohash) { + h = cache->dohash(current); + if ((h >= 0) && (h < cache->max_hash)) { + /* get a free link and insert at top of hash list */ + link = cache->free_hash; + if (link) { + cache->free_hash = link->next; + first = cache->first_hash[h]; + if (first) + link->next = first; + else + link->next = NULL; + link->entry = current; + cache->first_hash[h] = link; + } else { + ntfs_log_error("No more hash entries," + " cache %s hashing dropped\n", + cache->name); + cache->dohash = (cache_hash)NULL; + } + } else { + ntfs_log_error("Illegal hash value," + " cache %s hashing dropped\n", + cache->name); + cache->dohash = (cache_hash)NULL; + } + } +} + +/* + * Drop a hash index when a record is about to be deleted + */ + +static void drophashindex(struct CACHE_HEADER *cache, + const struct CACHED_GENERIC *current, int hash) +{ + struct HASH_ENTRY *link; + struct HASH_ENTRY *previous; + + if (cache->dohash) { + if ((hash >= 0) && (hash < cache->max_hash)) { + /* find the link and unlink */ + link = cache->first_hash[hash]; + previous = (struct HASH_ENTRY*)NULL; + while (link && (link->entry != current)) { + previous = link; + link = link->next; + } + if (link) { + if (previous) + previous->next = link->next; + else + cache->first_hash[hash] = link->next; + link->next = cache->free_hash; + cache->free_hash = link; + } else { + ntfs_log_error("Bad hash list," + " cache %s hashing dropped\n", + cache->name); + cache->dohash = (cache_hash)NULL; + } + } else { + ntfs_log_error("Illegal hash value," + " cache %s hashing dropped\n", + cache->name); + cache->dohash = (cache_hash)NULL; + } + } +} + +/* + * Fetch an entry from cache + * + * returns the cache entry, or NULL if not available + * The returned entry may be modified, but not freed + */ + +struct CACHED_GENERIC *ntfs_fetch_cache(struct CACHE_HEADER *cache, + const struct CACHED_GENERIC *wanted, cache_compare compare) +{ + struct CACHED_GENERIC *current; + struct CACHED_GENERIC *previous; + struct HASH_ENTRY *link; + int h; + + current = (struct CACHED_GENERIC*)NULL; + if (cache) { + if (cache->dohash) { + /* + * When possible, use the hash table to + * locate the entry if present + */ + h = cache->dohash(wanted); + link = cache->first_hash[h]; + while (link && compare(link->entry, wanted)) + link = link->next; + if (link) + current = link->entry; + } + if (!cache->dohash) { + /* + * Search sequentially in LRU list if no hash table + * or if hashing has just failed + */ + current = cache->most_recent_entry; + while (current + && compare(current, wanted)) { + current = current->next; + } + } + if (current) { + previous = current->previous; + cache->hits++; + if (previous) { + /* + * found and not at head of list, unlink from current + * position and relink as head of list + */ + previous->next = current->next; + if (current->next) + current->next->previous + = current->previous; + else + cache->oldest_entry + = current->previous; + current->next = cache->most_recent_entry; + current->previous + = (struct CACHED_GENERIC*)NULL; + cache->most_recent_entry->previous = current; + cache->most_recent_entry = current; + } + } + cache->reads++; + } + return (current); +} + +/* + * Enter an inode number into cache + * returns the cache entry or NULL if not possible + */ + +struct CACHED_GENERIC *ntfs_enter_cache(struct CACHE_HEADER *cache, + const struct CACHED_GENERIC *item, + cache_compare compare) +{ + struct CACHED_GENERIC *current; + struct CACHED_GENERIC *before; + struct HASH_ENTRY *link; + int h; + + current = (struct CACHED_GENERIC*)NULL; + if (cache) { + if (cache->dohash) { + /* + * When possible, use the hash table to + * find out whether the entry if present + */ + h = cache->dohash(item); + link = cache->first_hash[h]; + while (link && compare(link->entry, item)) + link = link->next; + if (link) { + current = link->entry; + } + } + if (!cache->dohash) { + /* + * Search sequentially in LRU list to locate the end, + * and find out whether the entry is already in list + * As we normally go to the end, no statistics is + * kept. + */ + current = cache->most_recent_entry; + while (current + && compare(current, item)) { + current = current->next; + } + } + + if (!current) { + /* + * Not in list, get a free entry or reuse the + * last entry, and relink as head of list + * Note : we assume at least three entries, so + * before, previous and first are different when + * an entry is reused. + */ + + if (cache->free_entry) { + current = cache->free_entry; + cache->free_entry = cache->free_entry->next; + if (item->varsize) { + current->variable = ntfs_malloc( + item->varsize); + } else + current->variable = (void*)NULL; + current->varsize = item->varsize; + if (!cache->oldest_entry) + cache->oldest_entry = current; + } else { + /* reusing the oldest entry */ + current = cache->oldest_entry; + before = current->previous; + before->next = (struct CACHED_GENERIC*)NULL; + if (cache->dohash) + drophashindex(cache,current, + cache->dohash(current)); + if (cache->dofree) + cache->dofree(current); + cache->oldest_entry = current->previous; + if (item->varsize) { + if (current->varsize) + current->variable = realloc( + current->variable, + item->varsize); + else + current->variable = ntfs_malloc( + item->varsize); + } else { + if (current->varsize) + free(current->variable); + current->variable = (void*)NULL; + } + current->varsize = item->varsize; + } + current->next = cache->most_recent_entry; + current->previous = (struct CACHED_GENERIC*)NULL; + if (cache->most_recent_entry) + cache->most_recent_entry->previous = current; + cache->most_recent_entry = current; + memcpy(current->fixed, item->fixed, cache->fixed_size); + if (item->varsize) { + if (current->variable) { + memcpy(current->variable, + item->variable, item->varsize); + } else { + /* + * no more memory for variable part + * recycle entry in free list + * not an error, just uncacheable + */ + cache->most_recent_entry = current->next; + current->next = cache->free_entry; + cache->free_entry = current; + current = (struct CACHED_GENERIC*)NULL; + } + } else { + current->variable = (void*)NULL; + current->varsize = 0; + } + if (cache->dohash && current) + inserthashindex(cache,current); + } + cache->writes++; + } + return (current); +} + +/* + * Invalidate a cache entry + * The entry is moved to the free entry list + * A specific function may be called for entry deletion + */ + +static void do_invalidate(struct CACHE_HEADER *cache, + struct CACHED_GENERIC *current, int flags) +{ + struct CACHED_GENERIC *previous; + + previous = current->previous; + if ((flags & CACHE_FREE) && cache->dofree) + cache->dofree(current); + /* + * Relink into free list + */ + if (current->next) + current->next->previous = current->previous; + else + cache->oldest_entry = current->previous; + if (previous) + previous->next = current->next; + else + cache->most_recent_entry = current->next; + current->next = cache->free_entry; + cache->free_entry = current; + if (current->variable) + free(current->variable); + current->varsize = 0; + } + + +/* + * Invalidate entries in cache + * + * Several entries may have to be invalidated (at least for inodes + * associated to directories which have been renamed), a different + * compare function may be provided to select entries to invalidate + * + * Returns the number of deleted entries, this can be used by + * the caller to signal a cache corruption if the entry was + * supposed to be found. + */ + +int ntfs_invalidate_cache(struct CACHE_HEADER *cache, + const struct CACHED_GENERIC *item, cache_compare compare, + int flags) +{ + struct CACHED_GENERIC *current; + struct CACHED_GENERIC *previous; + struct CACHED_GENERIC *next; + struct HASH_ENTRY *link; + int count; + int h; + + current = (struct CACHED_GENERIC*)NULL; + count = 0; + if (cache) { + if (!(flags & CACHE_NOHASH) && cache->dohash) { + /* + * When possible, use the hash table to + * find out whether the entry if present + */ + h = cache->dohash(item); + link = cache->first_hash[h]; + while (link) { + if (compare(link->entry, item)) + link = link->next; + else { + current = link->entry; + link = link->next; + if (current) { + drophashindex(cache,current,h); + do_invalidate(cache, + current,flags); + count++; + } + } + } + } + if ((flags & CACHE_NOHASH) || !cache->dohash) { + /* + * Search sequentially in LRU list + */ + current = cache->most_recent_entry; + previous = (struct CACHED_GENERIC*)NULL; + while (current) { + if (!compare(current, item)) { + next = current->next; + if (cache->dohash) + drophashindex(cache,current, + cache->dohash(current)); + do_invalidate(cache,current,flags); + current = next; + count++; + } else { + previous = current; + current = current->next; + } + } + } + } + return (count); +} + +int ntfs_remove_cache(struct CACHE_HEADER *cache, + struct CACHED_GENERIC *item, int flags) +{ + int count; + + count = 0; + if (cache) { + if (cache->dohash) + drophashindex(cache,item,cache->dohash(item)); + do_invalidate(cache,item,flags); + count++; + } + return (count); +} + +/* + * Free memory allocated to a cache + */ + +static void ntfs_free_cache(struct CACHE_HEADER *cache) +{ + struct CACHED_GENERIC *entry; + + if (cache) { + for (entry=cache->most_recent_entry; entry; entry=entry->next) { + if (cache->dofree) + cache->dofree(entry); + if (entry->variable) + free(entry->variable); + } + free(cache); + } +} + +/* + * Create a cache + * + * Returns the cache header, or NULL if the cache could not be created + */ + +static struct CACHE_HEADER *ntfs_create_cache(const char *name, + cache_free dofree, cache_hash dohash, + int full_item_size, + int item_count, int max_hash) +{ + struct CACHE_HEADER *cache; + struct CACHED_GENERIC *pc; + struct CACHED_GENERIC *qc; + struct HASH_ENTRY *ph; + struct HASH_ENTRY *qh; + struct HASH_ENTRY **px; + size_t size; + int i; + + size = sizeof(struct CACHE_HEADER) + item_count*full_item_size; + if (max_hash) + size += item_count*sizeof(struct HASH_ENTRY) + + max_hash*sizeof(struct HASH_ENTRY*); + cache = (struct CACHE_HEADER*)ntfs_malloc(size); + if (cache) { + /* header */ + cache->name = name; + cache->dofree = dofree; + if (dohash && max_hash) { + cache->dohash = dohash; + cache->max_hash = max_hash; + } else { + cache->dohash = (cache_hash)NULL; + cache->max_hash = 0; + } + cache->fixed_size = full_item_size - sizeof(struct CACHED_GENERIC); + cache->reads = 0; + cache->writes = 0; + cache->hits = 0; + /* chain the data entries, and mark an invalid entry */ + cache->most_recent_entry = (struct CACHED_GENERIC*)NULL; + cache->oldest_entry = (struct CACHED_GENERIC*)NULL; + cache->free_entry = &cache->entry[0]; + pc = &cache->entry[0]; + for (i=0; i<(item_count - 1); i++) { + qc = (struct CACHED_GENERIC*)((char*)pc + + full_item_size); + pc->next = qc; + pc->variable = (void*)NULL; + pc->varsize = 0; + pc = qc; + } + /* special for the last entry */ + pc->next = (struct CACHED_GENERIC*)NULL; + pc->variable = (void*)NULL; + pc->varsize = 0; + + if (max_hash) { + /* chain the hash entries */ + ph = (struct HASH_ENTRY*)(((char*)pc) + full_item_size); + cache->free_hash = ph; + for (i=0; i<(item_count - 1); i++) { + qh = &ph[1]; + ph->next = qh; + ph = qh; + } + /* special for the last entry */ + if (item_count) { + ph->next = (struct HASH_ENTRY*)NULL; + } + /* create and initialize the hash indexes */ + px = (struct HASH_ENTRY**)&ph[1]; + cache->first_hash = px; + for (i=0; ifree_hash = (struct HASH_ENTRY*)NULL; + cache->first_hash = (struct HASH_ENTRY**)NULL; + } + } + return (cache); +} + +/* + * Create all LRU caches + * + * No error return, if creation is not possible, cacheing will + * just be not available + */ + +void ntfs_create_lru_caches(ntfs_volume *vol) +{ +#if CACHE_INODE_SIZE + /* inode cache */ + vol->xinode_cache = ntfs_create_cache("inode",(cache_free)NULL, + ntfs_dir_inode_hash, sizeof(struct CACHED_INODE), + CACHE_INODE_SIZE, 2*CACHE_INODE_SIZE); +#endif +#if CACHE_NIDATA_SIZE + /* idata cache */ + vol->nidata_cache = ntfs_create_cache("nidata", + ntfs_inode_nidata_free, ntfs_inode_nidata_hash, + sizeof(struct CACHED_NIDATA), + CACHE_NIDATA_SIZE, 2*CACHE_NIDATA_SIZE); +#endif +#if CACHE_LOOKUP_SIZE + /* lookup cache */ + vol->lookup_cache = ntfs_create_cache("lookup", + (cache_free)NULL, ntfs_dir_lookup_hash, + sizeof(struct CACHED_LOOKUP), + CACHE_LOOKUP_SIZE, 2*CACHE_LOOKUP_SIZE); +#endif + vol->securid_cache = ntfs_create_cache("securid",(cache_free)NULL, + (cache_hash)NULL,sizeof(struct CACHED_SECURID), CACHE_SECURID_SIZE, 0); +#if CACHE_LEGACY_SIZE + vol->legacy_cache = ntfs_create_cache("legacy",(cache_free)NULL, + (cache_hash)NULL, sizeof(struct CACHED_PERMISSIONS_LEGACY), CACHE_LEGACY_SIZE, 0); +#endif +} + +/* + * Free all LRU caches + */ + +void ntfs_free_lru_caches(ntfs_volume *vol) +{ +#if CACHE_INODE_SIZE + ntfs_free_cache(vol->xinode_cache); +#endif +#if CACHE_NIDATA_SIZE + ntfs_free_cache(vol->nidata_cache); +#endif +#if CACHE_LOOKUP_SIZE + ntfs_free_cache(vol->lookup_cache); +#endif + ntfs_free_cache(vol->securid_cache); +#if CACHE_LEGACY_SIZE + ntfs_free_cache(vol->legacy_cache); +#endif +} diff --git a/libntfs-3g/collate.c b/libntfs-3g/collate.c new file mode 100755 index 0000000..5f7a015 --- a/dev/null +++ b/libntfs-3g/collate.c @@ -0,0 +1,271 @@ +/** + * collate.c - NTFS collation handling. Originated from the Linux-NTFS project. + * + * Copyright (c) 2004 Anton Altaparmakov + * Copyright (c) 2005 Yura Pakhuchiy + * + * This program/include file 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/include file 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 (in the main directory of the NTFS-3G + * distribution in the file COPYING); if not, write to the Free Software + * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_ERRNO_H +#include +#endif + +#include "attrib.h" +#include "index.h" +#include "collate.h" +#include "debug.h" +#include "unistr.h" +#include "logging.h" + +/** + * ntfs_collate_binary - Which of two binary objects should be listed first + * @vol: unused + * @data1: + * @data1_len: + * @data2: + * @data2_len: + * + * Description... + * + * Returns: + */ +static int ntfs_collate_binary(ntfs_volume *vol __attribute__((unused)), + const void *data1, const int data1_len, + const void *data2, const int data2_len) +{ + int rc; + + ntfs_log_trace("Entering.\n"); + rc = memcmp(data1, data2, min(data1_len, data2_len)); + if (!rc && (data1_len != data2_len)) { + if (data1_len < data2_len) + rc = -1; + else + rc = 1; + } + ntfs_log_trace("Done, returning %i.\n", rc); + return rc; +} + +/** + * ntfs_collate_ntofs_ulong - Which of two long ints should be listed first + * @vol: unused + * @data1: + * @data1_len: + * @data2: + * @data2_len: + * + * Description... + * + * Returns: + */ +static int ntfs_collate_ntofs_ulong(ntfs_volume *vol __attribute__((unused)), + const void *data1, const int data1_len, + const void *data2, const int data2_len) +{ + int rc; + u32 d1, d2; + + ntfs_log_trace("Entering.\n"); + if (data1_len != data2_len || data1_len != 4) { + ntfs_log_error("data1_len or/and data2_len not equal to 4.\n"); + return NTFS_COLLATION_ERROR; + } + d1 = le32_to_cpup(data1); + d2 = le32_to_cpup(data2); + if (d1 < d2) + rc = -1; + else { + if (d1 == d2) + rc = 0; + else + rc = 1; + } + ntfs_log_trace("Done, returning %i.\n", rc); + return rc; +} + +/** + * ntfs_collate_ntofs_ulongs - Which of two le32 arrays should be listed first + * + * Returns: -1, 0 or 1 depending of how the arrays compare + */ + +static int ntfs_collate_ntofs_ulongs(ntfs_volume *vol __attribute__((unused)), + const void *data1, const int data1_len, + const void *data2, const int data2_len) +{ + int rc; + int len; + const le32 *p1, *p2; + u32 d1, d2; + + ntfs_log_trace("Entering.\n"); + if ((data1_len != data2_len) || (data1_len <= 0) || (data1_len & 3)) { + ntfs_log_error("data1_len or data2_len not valid\n"); + return NTFS_COLLATION_ERROR; + } + p1 = (const le32*)data1; + p2 = (const le32*)data2; + len = data1_len; + do { + d1 = le32_to_cpup(p1); + p1++; + d2 = le32_to_cpup(p2); + p2++; + } while ((d1 == d2) && ((len -= 4) > 0)); + if (d1 < d2) + rc = -1; + else { + if (d1 == d2) + rc = 0; + else + rc = 1; + } + ntfs_log_trace("Done, returning %i.\n", rc); + return rc; +} + +/** + * ntfs_collate_ntofs_security_hash - Which of two security descriptors + * should be listed first + * @vol: unused + * @data1: + * @data1_len: + * @data2: + * @data2_len: + * + * JPA compare two security hash keys made of two unsigned le32 + * + * Returns: -1, 0 or 1 depending of how the keys compare + */ +static int ntfs_collate_ntofs_security_hash(ntfs_volume *vol __attribute__((unused)), + const void *data1, const int data1_len, + const void *data2, const int data2_len) +{ + int rc; + u32 d1, d2; + const le32 *p1, *p2; + + ntfs_log_trace("Entering.\n"); + if (data1_len != data2_len || data1_len != 8) { + ntfs_log_error("data1_len or/and data2_len not equal to 8.\n"); + return NTFS_COLLATION_ERROR; + } + p1 = (const le32*)data1; + p2 = (const le32*)data2; + d1 = le32_to_cpup(p1); + d2 = le32_to_cpup(p2); + if (d1 < d2) + rc = -1; + else { + if (d1 > d2) + rc = 1; + else { + p1++; + p2++; + d1 = le32_to_cpup(p1); + d2 = le32_to_cpup(p2); + if (d1 < d2) + rc = -1; + else { + if (d1 > d2) + rc = 1; + else + rc = 0; + } + } + } + ntfs_log_trace("Done, returning %i.\n", rc); + return rc; +} + +/** + * ntfs_collate_file_name - Which of two filenames should be listed first + * @vol: + * @data1: + * @data1_len: unused + * @data2: + * @data2_len: unused + * + * Description... + * + * Returns: + */ +static int ntfs_collate_file_name(ntfs_volume *vol, + const void *data1, const int data1_len __attribute__((unused)), + const void *data2, const int data2_len __attribute__((unused))) +{ + const FILE_NAME_ATTR *file_name_attr1; + const FILE_NAME_ATTR *file_name_attr2; + int rc; + + ntfs_log_trace("Entering.\n"); + file_name_attr1 = (const FILE_NAME_ATTR*)data1; + file_name_attr2 = (const FILE_NAME_ATTR*)data2; + rc = ntfs_names_full_collate( + (ntfschar*)&file_name_attr1->file_name, + file_name_attr1->file_name_length, + (ntfschar*)&file_name_attr2->file_name, + file_name_attr2->file_name_length, + CASE_SENSITIVE, vol->upcase, vol->upcase_len); + ntfs_log_trace("Done, returning %i.\n", rc); + return rc; +} + +/* + * Get a pointer to appropriate collation function. + * + * Returns NULL if the needed function is not implemented + */ + +COLLATE ntfs_get_collate_function(COLLATION_RULES cr) +{ + COLLATE collate; + + switch (cr) { + case COLLATION_BINARY : + collate = ntfs_collate_binary; + break; + case COLLATION_FILE_NAME : + collate = ntfs_collate_file_name; + break; + case COLLATION_NTOFS_SECURITY_HASH : + collate = ntfs_collate_ntofs_security_hash; + break; + case COLLATION_NTOFS_ULONG : + collate = ntfs_collate_ntofs_ulong; + break; + case COLLATION_NTOFS_ULONGS : + collate = ntfs_collate_ntofs_ulongs; + break; + default : + errno = EOPNOTSUPP; + collate = (COLLATE)NULL; + break; + } + return (collate); +} diff --git a/libntfs-3g/compat.c b/libntfs-3g/compat.c new file mode 100755 index 0000000..63114a4 --- a/dev/null +++ b/libntfs-3g/compat.c @@ -0,0 +1,250 @@ +/** + * compat.c - Tweaks for Windows compatibility + * + * Copyright (c) 2002 Richard Russon + * Copyright (c) 2002-2004 Anton Altaparmakov + * + * This program/include file 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/include file 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 (in the main directory of the NTFS-3G + * distribution in the file COPYING); if not, write to the Free Software + * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "compat.h" + +#ifndef HAVE_FFS +/** + * ffs - Find the first set bit in an int + * @x: + * + * Description... + * + * Returns: + */ +int ffs(int x) +{ + int r = 1; + + if (!x) + return 0; + if (!(x & 0xffff)) { + x >>= 16; + r += 16; + } + if (!(x & 0xff)) { + x >>= 8; + r += 8; + } + if (!(x & 0xf)) { + x >>= 4; + r += 4; + } + if (!(x & 3)) { + x >>= 2; + r += 2; + } + if (!(x & 1)) { + x >>= 1; + r += 1; + } + return r; +} +#endif /* HAVE_FFS */ + +#ifndef HAVE_DAEMON +/* ************************************************************ + * From: src.opensolaris.org + * src/lib/libresolv2/common/bsd/daemon.c + */ +/* + * Copyright (c) 1997-2000 by Sun Microsystems, Inc. + * All rights reserved. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static const char sccsid[] = "@(#)daemon.c 8.1 (Berkeley) 6/4/93"; +static const char rcsid[] = "$Id: compat.c,v 1.1.1.1.2.1 2008-08-16 15:17:44 jpandre Exp $"; +#endif /* LIBC_SCCS and not lint */ + +/* + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_FCNTL_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif + +int daemon(int nochdir, int noclose) { + int fd; + + switch (fork()) { + case -1: + return (-1); + case 0: + break; + default: + _exit(0); + } + + if (setsid() == -1) + return (-1); + + if (!nochdir) + (void)chdir("/"); + + if (!noclose && (fd = open("/dev/null", O_RDWR, 0)) != -1) { + (void)dup2(fd, 0); + (void)dup2(fd, 1); + (void)dup2(fd, 2); + if (fd > 2) + (void)close (fd); + } + return (0); +} +/* + * End: src/lib/libresolv2/common/bsd/daemon.c + *************************************************************/ +#endif /* HAVE_DAEMON */ + +#ifndef HAVE_STRSEP +/* ************************************************************ + * From: src.opensolaris.org + * src/lib/libresolv2/common/bsd/strsep.c + */ +/* + * Copyright (c) 1997, by Sun Microsystems, Inc. + * All rights reserved. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static const char sccsid[] = "strsep.c 8.1 (Berkeley) 6/4/93"; +static const char rcsid[] = "$Id: compat.c,v 1.1.1.1.2.1 2008-08-16 15:17:44 jpandre Exp $"; +#endif /* LIBC_SCCS and not lint */ + +/* + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_STDIO_H +#include +#endif + +/* + * Get next token from string *stringp, where tokens are possibly-empty + * strings separated by characters from delim. + * + * Writes NULs into the string at *stringp to end tokens. + * delim need not remain constant from call to call. + * On return, *stringp points past the last NUL written (if there might + * be further tokens), or is NULL (if there are definitely no more tokens). + * + * If *stringp is NULL, strsep returns NULL. + */ +char *strsep(char **stringp, const char *delim) { + char *s; + const char *spanp; + int c, sc; + char *tok; + + if ((s = *stringp) == NULL) + return (NULL); + for (tok = s;;) { + c = *s++; + spanp = delim; + do { + if ((sc = *spanp++) == c) { + if (c == 0) + s = NULL; + else + s[-1] = 0; + *stringp = s; + return (tok); + } + } while (sc != 0); + } + /* NOTREACHED */ +} + +/* + * End: src/lib/libresolv2/common/bsd/strsep.c + *************************************************************/ +#endif /* HAVE_STRSEP */ + diff --git a/libntfs-3g/compress.c b/libntfs-3g/compress.c new file mode 100755 index 0000000..14471b8 --- a/dev/null +++ b/libntfs-3g/compress.c @@ -0,0 +1,1431 @@ +/** + * compress.c - Compressed attribute handling code. Originated from the Linux-NTFS + * project. + * + * Copyright (c) 2004-2005 Anton Altaparmakov + * Copyright (c) 2004-2006 Szabolcs Szakacsits + * Copyright (c) 2005 Yura Pakhuchiy + * Copyright (c) 2009 Jean-Pierre Andre + * + * This program/include file 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/include file 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 (in the main directory of the NTFS-3G + * distribution in the file COPYING); if not, write to the Free Software + * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * A part of the compression algorithm is based on lzhuf.c whose header + * describes the roles of the original authors (with no apparent copyright + * notice, and according to http://home.earthlink.net/~neilbawd/pall.html + * this was put into public domain in 1988 by Haruhiko OKUMURA). + * + * LZHUF.C English version 1.0 + * Based on Japanese version 29-NOV-1988 + * LZSS coded by Haruhiko OKUMURA + * Adaptive Huffman Coding coded by Haruyasu YOSHIZAKI + * Edited and translated to English by Kenji RIKITAKE + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_STDIO_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_ERRNO_H +#include +#endif + +#include "attrib.h" +#include "debug.h" +#include "volume.h" +#include "types.h" +#include "layout.h" +#include "runlist.h" +#include "compress.h" +#include "lcnalloc.h" +#include "logging.h" +#include "misc.h" + +/** + * enum ntfs_compression_constants - constants used in the compression code + */ +typedef enum { + /* Token types and access mask. */ + NTFS_SYMBOL_TOKEN = 0, + NTFS_PHRASE_TOKEN = 1, + NTFS_TOKEN_MASK = 1, + + /* Compression sub-block constants. */ + NTFS_SB_SIZE_MASK = 0x0fff, + NTFS_SB_SIZE = 0x1000, + NTFS_SB_IS_COMPRESSED = 0x8000, +} ntfs_compression_constants; + +#define THRESHOLD 3 /* minimal match length for compression */ +#define NIL NTFS_SB_SIZE /* End of tree's node */ + +struct COMPRESS_CONTEXT { + const unsigned char *inbuf; + unsigned int len; + unsigned int nbt; + int match_position; + unsigned int match_length; + u16 lson[NTFS_SB_SIZE + 1]; + u16 rson[NTFS_SB_SIZE + 257]; + u16 dad[NTFS_SB_SIZE + 1]; +} ; + +/* + * Initialize the match tree + */ + +static void ntfs_init_compress_tree(struct COMPRESS_CONTEXT *pctx) +{ + int i; + + for (i = NTFS_SB_SIZE + 1; i <= NTFS_SB_SIZE + 256; i++) + pctx->rson[i] = NIL; /* root */ + for (i = 0; i < NTFS_SB_SIZE; i++) + pctx->dad[i] = NIL; /* node */ +} + +/* + * Insert a new node into match tree for quickly locating + * further similar strings + */ + +static void ntfs_new_node (struct COMPRESS_CONTEXT *pctx, + unsigned int r) +{ + unsigned int pp; + BOOL less; + BOOL done; + const unsigned char *key; + int c; + unsigned int mxi; + unsigned int mxl; + + mxl = (1 << (16 - pctx->nbt)) + 2; + less = FALSE; + done = FALSE; + key = &pctx->inbuf[r]; + pp = NTFS_SB_SIZE + 1 + key[0]; + pctx->rson[r] = pctx->lson[r] = NIL; + pctx->match_length = 0; + do { + if (!less) { + if (pctx->rson[pp] != NIL) + pp = pctx->rson[pp]; + else { + pctx->rson[pp] = r; + pctx->dad[r] = pp; + done = TRUE; + } + } else { + if (pctx->lson[pp] != NIL) + pp = pctx->lson[pp]; + else { + pctx->lson[pp] = r; + pctx->dad[r] = pp; + done = TRUE; + } + } + if (!done) { + register unsigned int i; + register const unsigned char *p1,*p2; + + i = 1; + p1 = key; + p2 = &pctx->inbuf[pp]; + mxi = NTFS_SB_SIZE - r; + do { + } while ((p1[i] == p2[i]) && (++i < mxi)); + less = (i < mxi) && (p1[i] < p2[i]); + if (i >= THRESHOLD) { + if (i > pctx->match_length) { + pctx->match_position = + r - pp + 2*NTFS_SB_SIZE - 1; + if ((pctx->match_length = i) > mxl) { + i = pctx->rson[pp]; + pctx->rson[r] = i; + pctx->dad[i] = r; + i = pctx->lson[pp]; + pctx->lson[r] = i; + pctx->dad[i] = r; + i = pctx->dad[pp]; + pctx->dad[r] = i; + if (pctx->rson[i] == pp) + pctx->rson[i] = r; + else + pctx->lson[i] = r; + pctx->dad[pp] = NIL; /* remove pp */ + done = TRUE; + pctx->match_length = mxl; + } + } else + if ((i == pctx->match_length) + && ((c = (r - pp + 2*NTFS_SB_SIZE - 1)) + < pctx->match_position)) + pctx->match_position = c; + } + } + } while (!done); +} + +/* + * Search for the longest previous string matching the + * current one + * + * Returns the end of the longest current string which matched + * or zero if there was a bug + */ + +static unsigned int ntfs_nextmatch(struct COMPRESS_CONTEXT *pctx, unsigned int rr, int dd) +{ + unsigned int bestlen = 0; + + do { + rr++; + if (pctx->match_length > 0) + pctx->match_length--; + if (!pctx->len) { + ntfs_log_error("compress bug : void run\n"); + goto bug; + } + if (--pctx->len) { + if (rr >= NTFS_SB_SIZE) { + ntfs_log_error("compress bug : buffer overflow\n"); + goto bug; + } + if (((rr + bestlen) < NTFS_SB_SIZE)) { + while ((unsigned int)(1 << pctx->nbt) <= (rr - 1)) + pctx->nbt++; + ntfs_new_node(pctx,rr); + if (pctx->match_length > bestlen) + bestlen = pctx->match_length; + } else + if (dd > 0) { + rr += dd; + if ((int)pctx->match_length > dd) + pctx->match_length -= dd; + else + pctx->match_length = 0; + if ((int)pctx->len < dd) { + ntfs_log_error("compress bug : run overflows\n"); + goto bug; + } + pctx->len -= dd; + dd = 0; + } + } + } while (dd-- > 0); + return (rr); +bug : + return (0); +} + +/* + * Compress an input block + * + * Returns the size of the compressed block (including header) + * or zero if there was an error + */ + +static unsigned int ntfs_compress_block(const char *inbuf, unsigned int size, char *outbuf) +{ + struct COMPRESS_CONTEXT *pctx; + char *ptag; + int dd; + unsigned int rr; + unsigned int last_match_length; + unsigned int q; + unsigned int xout; + unsigned int ntag; + + pctx = (struct COMPRESS_CONTEXT*)malloc(sizeof(struct COMPRESS_CONTEXT)); + if (pctx) { + pctx->inbuf = (const unsigned char*)inbuf; + ntfs_init_compress_tree(pctx); + xout = 2; + ntag = 0; + ptag = &outbuf[xout++]; + *ptag = 0; + rr = 0; + pctx->nbt = 4; + pctx->len = size; + pctx->match_length = 0; + ntfs_new_node(pctx,0); + do { + if (pctx->match_length > pctx->len) + pctx->match_length = pctx->len; + if (pctx->match_length < THRESHOLD) { + pctx->match_length = 1; + if (ntag >= 8) { + ntag = 0; + ptag = &outbuf[xout++]; + *ptag = 0; + } + outbuf[xout++] = inbuf[rr]; + ntag++; + } else { + while ((unsigned int)(1 << pctx->nbt) <= (rr - 1)) + pctx->nbt++; + q = (pctx->match_position << (16 - pctx->nbt)) + + pctx->match_length - THRESHOLD; + if (ntag >= 8) { + ntag = 0; + ptag = &outbuf[xout++]; + *ptag = 0; + } + *ptag |= 1 << ntag++; + outbuf[xout++] = q & 255; + outbuf[xout++] = (q >> 8) & 255; + } + last_match_length = pctx->match_length; + dd = last_match_length; + if (dd-- > 0) { + rr = ntfs_nextmatch(pctx,rr,dd); + if (!rr) + goto bug; + } + /* + * stop if input is exhausted or output has exceeded + * the maximum size. Two extra bytes have to be + * reserved in output buffer, as 3 bytes may be + * output in a loop. + */ + } while ((pctx->len > 0) + && (rr < size) && (xout < (NTFS_SB_SIZE + 2))); + /* uncompressed must be full size, so accept if better */ + if (xout < (NTFS_SB_SIZE + 2)) { + outbuf[0] = (xout - 3) & 255; + outbuf[1] = 0xb0 + (((xout - 3) >> 8) & 15); + } else { + memcpy(&outbuf[2],inbuf,size); + if (size < NTFS_SB_SIZE) + memset(&outbuf[size+2],0,NTFS_SB_SIZE - size); + outbuf[0] = 0xff; + outbuf[1] = 0x3f; + xout = NTFS_SB_SIZE + 2; + } + free(pctx); + } else { + xout = 0; + errno = ENOMEM; + } + return (xout); /* 0 for an error, > size if cannot compress */ +bug : + return (0); +} + +/** + * ntfs_decompress - decompress a compression block into an array of pages + * @dest: buffer to which to write the decompressed data + * @dest_size: size of buffer @dest in bytes + * @cb_start: compression block to decompress + * @cb_size: size of compression block @cb_start in bytes + * + * This decompresses the compression block @cb_start into the destination + * buffer @dest. + * + * @cb_start is a pointer to the compression block which needs decompressing + * and @cb_size is the size of @cb_start in bytes (8-64kiB). + * + * Return 0 if success or -EOVERFLOW on error in the compressed stream. + */ +static int ntfs_decompress(u8 *dest, const u32 dest_size, + u8 *const cb_start, const u32 cb_size) +{ + /* + * Pointers into the compressed data, i.e. the compression block (cb), + * and the therein contained sub-blocks (sb). + */ + u8 *cb_end = cb_start + cb_size; /* End of cb. */ + u8 *cb = cb_start; /* Current position in cb. */ + u8 *cb_sb_start = cb; /* Beginning of the current sb in the cb. */ + u8 *cb_sb_end; /* End of current sb / beginning of next sb. */ + /* Variables for uncompressed data / destination. */ + u8 *dest_end = dest + dest_size; /* End of dest buffer. */ + u8 *dest_sb_start; /* Start of current sub-block in dest. */ + u8 *dest_sb_end; /* End of current sb in dest. */ + /* Variables for tag and token parsing. */ + u8 tag; /* Current tag. */ + int token; /* Loop counter for the eight tokens in tag. */ + + ntfs_log_trace("Entering, cb_size = 0x%x.\n", (unsigned)cb_size); +do_next_sb: + ntfs_log_debug("Beginning sub-block at offset = %d in the cb.\n", + (int)(cb - cb_start)); + /* + * Have we reached the end of the compression block or the end of the + * decompressed data? The latter can happen for example if the current + * position in the compression block is one byte before its end so the + * first two checks do not detect it. + */ + if (cb == cb_end || !le16_to_cpup((le16*)cb) || dest == dest_end) { + ntfs_log_debug("Completed. Returning success (0).\n"); + return 0; + } + /* Setup offset for the current sub-block destination. */ + dest_sb_start = dest; + dest_sb_end = dest + NTFS_SB_SIZE; + /* Check that we are still within allowed boundaries. */ + if (dest_sb_end > dest_end) + goto return_overflow; + /* Does the minimum size of a compressed sb overflow valid range? */ + if (cb + 6 > cb_end) + goto return_overflow; + /* Setup the current sub-block source pointers and validate range. */ + cb_sb_start = cb; + cb_sb_end = cb_sb_start + (le16_to_cpup((le16*)cb) & NTFS_SB_SIZE_MASK) + + 3; + if (cb_sb_end > cb_end) + goto return_overflow; + /* Now, we are ready to process the current sub-block (sb). */ + if (!(le16_to_cpup((le16*)cb) & NTFS_SB_IS_COMPRESSED)) { + ntfs_log_debug("Found uncompressed sub-block.\n"); + /* This sb is not compressed, just copy it into destination. */ + /* Advance source position to first data byte. */ + cb += 2; + /* An uncompressed sb must be full size. */ + if (cb_sb_end - cb != NTFS_SB_SIZE) + goto return_overflow; + /* Copy the block and advance the source position. */ + memcpy(dest, cb, NTFS_SB_SIZE); + cb += NTFS_SB_SIZE; + /* Advance destination position to next sub-block. */ + dest += NTFS_SB_SIZE; + goto do_next_sb; + } + ntfs_log_debug("Found compressed sub-block.\n"); + /* This sb is compressed, decompress it into destination. */ + /* Forward to the first tag in the sub-block. */ + cb += 2; +do_next_tag: + if (cb == cb_sb_end) { + /* Check if the decompressed sub-block was not full-length. */ + if (dest < dest_sb_end) { + int nr_bytes = dest_sb_end - dest; + + ntfs_log_debug("Filling incomplete sub-block with zeroes.\n"); + /* Zero remainder and update destination position. */ + memset(dest, 0, nr_bytes); + dest += nr_bytes; + } + /* We have finished the current sub-block. */ + goto do_next_sb; + } + /* Check we are still in range. */ + if (cb > cb_sb_end || dest > dest_sb_end) + goto return_overflow; + /* Get the next tag and advance to first token. */ + tag = *cb++; + /* Parse the eight tokens described by the tag. */ + for (token = 0; token < 8; token++, tag >>= 1) { + u16 lg, pt, length, max_non_overlap; + register u16 i; + u8 *dest_back_addr; + + /* Check if we are done / still in range. */ + if (cb >= cb_sb_end || dest > dest_sb_end) + break; + /* Determine token type and parse appropriately.*/ + if ((tag & NTFS_TOKEN_MASK) == NTFS_SYMBOL_TOKEN) { + /* + * We have a symbol token, copy the symbol across, and + * advance the source and destination positions. + */ + *dest++ = *cb++; + /* Continue with the next token. */ + continue; + } + /* + * We have a phrase token. Make sure it is not the first tag in + * the sb as this is illegal and would confuse the code below. + */ + if (dest == dest_sb_start) + goto return_overflow; + /* + * Determine the number of bytes to go back (p) and the number + * of bytes to copy (l). We use an optimized algorithm in which + * we first calculate log2(current destination position in sb), + * which allows determination of l and p in O(1) rather than + * O(n). We just need an arch-optimized log2() function now. + */ + lg = 0; + for (i = dest - dest_sb_start - 1; i >= 0x10; i >>= 1) + lg++; + /* Get the phrase token into i. */ + pt = le16_to_cpup((le16*)cb); + /* + * Calculate starting position of the byte sequence in + * the destination using the fact that p = (pt >> (12 - lg)) + 1 + * and make sure we don't go too far back. + */ + dest_back_addr = dest - (pt >> (12 - lg)) - 1; + if (dest_back_addr < dest_sb_start) + goto return_overflow; + /* Now calculate the length of the byte sequence. */ + length = (pt & (0xfff >> lg)) + 3; + /* Verify destination is in range. */ + if (dest + length > dest_sb_end) + goto return_overflow; + /* The number of non-overlapping bytes. */ + max_non_overlap = dest - dest_back_addr; + if (length <= max_non_overlap) { + /* The byte sequence doesn't overlap, just copy it. */ + memcpy(dest, dest_back_addr, length); + /* Advance destination pointer. */ + dest += length; + } else { + /* + * The byte sequence does overlap, copy non-overlapping + * part and then do a slow byte by byte copy for the + * overlapping part. Also, advance the destination + * pointer. + */ + memcpy(dest, dest_back_addr, max_non_overlap); + dest += max_non_overlap; + dest_back_addr += max_non_overlap; + length -= max_non_overlap; + while (length--) + *dest++ = *dest_back_addr++; + } + /* Advance source position and continue with the next token. */ + cb += 2; + } + /* No tokens left in the current tag. Continue with the next tag. */ + goto do_next_tag; +return_overflow: + errno = EOVERFLOW; + ntfs_log_perror("Failed to decompress file"); + return -1; +} + +/** + * ntfs_is_cb_compressed - internal function, do not use + * + * This is a very specialised function determining if a cb is compressed or + * uncompressed. It is assumed that checking for a sparse cb has already been + * performed and that the cb is not sparse. It makes all sorts of other + * assumptions as well and hence it is not useful anywhere other than where it + * is used at the moment. Please, do not make this function available for use + * outside of compress.c as it is bound to confuse people and not do what they + * want. + * + * Return TRUE on errors so that the error will be detected later on in the + * code. Might be a bit confusing to debug but there really should never be + * errors coming from here. + */ +static BOOL ntfs_is_cb_compressed(ntfs_attr *na, runlist_element *rl, + VCN cb_start_vcn, int cb_clusters) +{ + /* + * The simplest case: the run starting at @cb_start_vcn contains + * @cb_clusters clusters which are all not sparse, thus the cb is not + * compressed. + */ +restart: + cb_clusters -= rl->length - (cb_start_vcn - rl->vcn); + while (cb_clusters > 0) { + /* Go to the next run. */ + rl++; + /* Map the next runlist fragment if it is not mapped. */ + if (rl->lcn < LCN_HOLE || !rl->length) { + cb_start_vcn = rl->vcn; + rl = ntfs_attr_find_vcn(na, rl->vcn); + if (!rl || rl->lcn < LCN_HOLE || !rl->length) + return TRUE; + /* + * If the runs were merged need to deal with the + * resulting partial run so simply restart. + */ + if (rl->vcn < cb_start_vcn) + goto restart; + } + /* If the current run is sparse, the cb is compressed. */ + if (rl->lcn == LCN_HOLE) + return TRUE; + /* If the whole cb is not sparse, it is not compressed. */ + if (rl->length >= cb_clusters) + return FALSE; + cb_clusters -= rl->length; + }; + /* All cb_clusters were not sparse thus the cb is not compressed. */ + return FALSE; +} + +/** + * ntfs_compressed_attr_pread - read from a compressed attribute + * @na: ntfs attribute to read from + * @pos: byte position in the attribute to begin reading from + * @count: number of bytes to read + * @b: output data buffer + * + * NOTE: You probably want to be using attrib.c::ntfs_attr_pread() instead. + * + * This function will read @count bytes starting at offset @pos from the + * compressed ntfs attribute @na into the data buffer @b. + * + * On success, return the number of successfully read bytes. If this number + * is lower than @count this means that the read reached end of file or that + * an error was encountered during the read so that the read is partial. + * 0 means end of file or nothing was read (also return 0 when @count is 0). + * + * On error and nothing has been read, return -1 with errno set appropriately + * to the return code of ntfs_pread(), or to EINVAL in case of invalid + * arguments. + */ +s64 ntfs_compressed_attr_pread(ntfs_attr *na, s64 pos, s64 count, void *b) +{ + s64 br, to_read, ofs, total, total2; + u64 cb_size_mask; + VCN start_vcn, vcn, end_vcn; + ntfs_volume *vol; + runlist_element *rl; + u8 *dest, *cb, *cb_pos, *cb_end; + u32 cb_size; + int err; + ATTR_FLAGS data_flags; + FILE_ATTR_FLAGS compression; + unsigned int nr_cbs, cb_clusters; + + ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x, pos 0x%llx, count 0x%llx.\n", + (unsigned long long)na->ni->mft_no, na->type, + (long long)pos, (long long)count); + data_flags = na->data_flags; + compression = na->ni->flags & FILE_ATTR_COMPRESSED; + if (!na || !na->ni || !na->ni->vol || !b + || ((data_flags & ATTR_COMPRESSION_MASK) + != ATTR_IS_COMPRESSED) + || pos < 0 || count < 0) { + errno = EINVAL; + return -1; + } + /* + * Encrypted attributes are not supported. We return access denied, + * which is what Windows NT4 does, too. + */ + if (NAttrEncrypted(na)) { + errno = EACCES; + return -1; + } + if (!count) + return 0; + /* Truncate reads beyond end of attribute. */ + if (pos + count > na->data_size) { + if (pos >= na->data_size) { + return 0; + } + count = na->data_size - pos; + } + /* If it is a resident attribute, simply use ntfs_attr_pread(). */ + if (!NAttrNonResident(na)) + return ntfs_attr_pread(na, pos, count, b); + total = total2 = 0; + /* Zero out reads beyond initialized size. */ + if (pos + count > na->initialized_size) { + if (pos >= na->initialized_size) { + memset(b, 0, count); + return count; + } + total2 = pos + count - na->initialized_size; + count -= total2; + memset((u8*)b + count, 0, total2); + } + vol = na->ni->vol; + cb_size = na->compression_block_size; + cb_size_mask = cb_size - 1UL; + cb_clusters = na->compression_block_clusters; + + /* Need a temporary buffer for each loaded compression block. */ + cb = (u8*)ntfs_malloc(cb_size); + if (!cb) + return -1; + + /* Need a temporary buffer for each uncompressed block. */ + dest = (u8*)ntfs_malloc(cb_size); + if (!dest) { + free(cb); + return -1; + } + /* + * The first vcn in the first compression block (cb) which we need to + * decompress. + */ + start_vcn = (pos & ~cb_size_mask) >> vol->cluster_size_bits; + /* Offset in the uncompressed cb at which to start reading data. */ + ofs = pos & cb_size_mask; + /* + * The first vcn in the cb after the last cb which we need to + * decompress. + */ + end_vcn = ((pos + count + cb_size - 1) & ~cb_size_mask) >> + vol->cluster_size_bits; + /* Number of compression blocks (cbs) in the wanted vcn range. */ + nr_cbs = (end_vcn - start_vcn) << vol->cluster_size_bits >> + na->compression_block_size_bits; + cb_end = cb + cb_size; +do_next_cb: + nr_cbs--; + cb_pos = cb; + vcn = start_vcn; + start_vcn += cb_clusters; + + /* Check whether the compression block is sparse. */ + rl = ntfs_attr_find_vcn(na, vcn); + if (!rl || rl->lcn < LCN_HOLE) { + free(cb); + free(dest); + if (total) + return total; + /* FIXME: Do we want EIO or the error code? (AIA) */ + errno = EIO; + return -1; + } + if (rl->lcn == LCN_HOLE) { + /* Sparse cb, zero out destination range overlapping the cb. */ + ntfs_log_debug("Found sparse compression block.\n"); + to_read = min(count, cb_size - ofs); + memset(b, 0, to_read); + ofs = 0; + total += to_read; + count -= to_read; + b = (u8*)b + to_read; + } else if (!ntfs_is_cb_compressed(na, rl, vcn, cb_clusters)) { + s64 tdata_size, tinitialized_size; + /* + * Uncompressed cb, read it straight into the destination range + * overlapping the cb. + */ + ntfs_log_debug("Found uncompressed compression block.\n"); + /* + * Read the uncompressed data into the destination buffer. + * NOTE: We cheat a little bit here by marking the attribute as + * not compressed in the ntfs_attr structure so that we can + * read the data by simply using ntfs_attr_pread(). (-8 + * NOTE: we have to modify data_size and initialized_size + * temporarily as well... + */ + to_read = min(count, cb_size - ofs); + ofs += vcn << vol->cluster_size_bits; + NAttrClearCompressed(na); + na->data_flags &= ~ATTR_COMPRESSION_MASK; + tdata_size = na->data_size; + tinitialized_size = na->initialized_size; + na->data_size = na->initialized_size = na->allocated_size; + do { + br = ntfs_attr_pread(na, ofs, to_read, b); + if (br < 0) { + err = errno; + na->data_size = tdata_size; + na->initialized_size = tinitialized_size; + na->ni->flags |= compression; + na->data_flags = data_flags; + free(cb); + free(dest); + if (total) + return total; + errno = err; + return br; + } + total += br; + count -= br; + b = (u8*)b + br; + to_read -= br; + ofs += br; + } while (to_read > 0); + na->data_size = tdata_size; + na->initialized_size = tinitialized_size; + na->ni->flags |= compression; + na->data_flags = data_flags; + ofs = 0; + } else { + s64 tdata_size, tinitialized_size; + + /* + * Compressed cb, decompress it into the temporary buffer, then + * copy the data to the destination range overlapping the cb. + */ + ntfs_log_debug("Found compressed compression block.\n"); + /* + * Read the compressed data into the temporary buffer. + * NOTE: We cheat a little bit here by marking the attribute as + * not compressed in the ntfs_attr structure so that we can + * read the raw, compressed data by simply using + * ntfs_attr_pread(). (-8 + * NOTE: We have to modify data_size and initialized_size + * temporarily as well... + */ + to_read = cb_size; + NAttrClearCompressed(na); + na->data_flags &= ~ATTR_COMPRESSION_MASK; + tdata_size = na->data_size; + tinitialized_size = na->initialized_size; + na->data_size = na->initialized_size = na->allocated_size; + do { + br = ntfs_attr_pread(na, + (vcn << vol->cluster_size_bits) + + (cb_pos - cb), to_read, cb_pos); + if (br < 0) { + err = errno; + na->data_size = tdata_size; + na->initialized_size = tinitialized_size; + na->ni->flags |= compression; + na->data_flags = data_flags; + free(cb); + free(dest); + if (total) + return total; + errno = err; + return br; + } + cb_pos += br; + to_read -= br; + } while (to_read > 0); + na->data_size = tdata_size; + na->initialized_size = tinitialized_size; + na->ni->flags |= compression; + na->data_flags = data_flags; + /* Just a precaution. */ + if (cb_pos + 2 <= cb_end) + *(u16*)cb_pos = 0; + ntfs_log_debug("Successfully read the compression block.\n"); + if (ntfs_decompress(dest, cb_size, cb, cb_size) < 0) { + err = errno; + free(cb); + free(dest); + if (total) + return total; + errno = err; + return -1; + } + to_read = min(count, cb_size - ofs); + memcpy(b, dest + ofs, to_read); + total += to_read; + count -= to_read; + b = (u8*)b + to_read; + ofs = 0; + } + /* Do we have more work to do? */ + if (nr_cbs) + goto do_next_cb; + /* We no longer need the buffers. */ + free(cb); + free(dest); + /* Return number of bytes read. */ + return total + total2; +} + +/* + * Read data from a set of clusters + * + * Returns the amount of data read + */ + +static u32 read_clusters(ntfs_volume *vol, const runlist_element *rl, + s64 offs, u32 to_read, char *inbuf) +{ + u32 count; + int xgot; + u32 got; + s64 xpos; + BOOL first; + char *xinbuf; + const runlist_element *xrl; + + got = 0; + xrl = rl; + xinbuf = inbuf; + first = TRUE; + do { + count = xrl->length << vol->cluster_size_bits; + xpos = xrl->lcn << vol->cluster_size_bits; + if (first) { + count -= offs; + xpos += offs; + } + if ((to_read - got) < count) + count = to_read - got; + xgot = ntfs_pread(vol->dev, xpos, count, xinbuf); + if (xgot == (int)count) { + got += count; + xpos += count; + xinbuf += count; + xrl++; + } + first = FALSE; + } while ((xgot == (int)count) && (got < to_read)); + return (got); +} + +/* + * Write data to a set of clusters + * + * Returns the amount of data written + */ + +static int write_clusters(ntfs_volume *vol, const runlist_element *rl, + s64 offs, int to_write, const char *outbuf) +{ + int count; + int put, xput; + s64 xpos; + BOOL first; + const char *xoutbuf; + const runlist_element *xrl; + + put = 0; + xrl = rl; + xoutbuf = outbuf; + first = TRUE; + do { + count = xrl->length << vol->cluster_size_bits; + xpos = xrl->lcn << vol->cluster_size_bits; + if (first) { + count -= offs; + xpos += offs; + } + if ((to_write - put) < count) + count = to_write - put; + xput = ntfs_pwrite(vol->dev, xpos, count, xoutbuf); + if (xput == count) { + put += count; + xpos += count; + xoutbuf += count; + xrl++; + } + first = FALSE; + } while ((xput == count) && (put < to_write)); + return (put); +} + + +/* + * Compress and write a set of blocks + * + * returns the size actually written (rounded to a full cluster) + * or 0 if all zeroes (nothing is written) + * or -1 if could not compress (nothing is written) + * or -2 if there were an irrecoverable error (errno set) + */ + +static int ntfs_comp_set(ntfs_attr *na, runlist_element *rl, + s64 offs, unsigned int insz, const char *inbuf) +{ + ntfs_volume *vol; + char *outbuf; + char *pbuf; + unsigned int compsz; + int written; + int rounded; + unsigned int clsz; + unsigned int p; + unsigned int sz; + unsigned int bsz; + BOOL fail; + BOOL allzeroes; + /* a single compressed zero */ + static char onezero[] = { 0x01, 0xb0, 0x00, 0x00 } ; + /* a couple of compressed zeroes */ + static char twozeroes[] = { 0x02, 0xb0, 0x00, 0x00, 0x00 } ; + /* more compressed zeroes, to be followed by some count */ + static char morezeroes[] = { 0x03, 0xb0, 0x02, 0x00 } ; + + vol = na->ni->vol; + written = -1; /* default return */ + clsz = 1 << vol->cluster_size_bits; + /* may need 2 extra bytes per block and 2 more bytes */ + outbuf = (char*)ntfs_malloc(na->compression_block_size + + 2*(na->compression_block_size/NTFS_SB_SIZE) + + 2); + if (outbuf) { + fail = FALSE; + compsz = 0; + allzeroes = TRUE; + for (p=0; (p na->compression_block_size)) + fail = TRUE; + else { + if (allzeroes) { + /* check whether this is all zeroes */ + switch (sz) { + case 4 : + allzeroes = !memcmp( + pbuf,onezero,4); + break; + case 5 : + allzeroes = !memcmp( + pbuf,twozeroes,5); + break; + case 6 : + allzeroes = !memcmp( + pbuf,morezeroes,4); + break; + default : + allzeroes = FALSE; + break; + } + } + compsz += sz; + } + } + if (!fail && !allzeroes) { + /* add a couple of null bytes, space has been checked */ + outbuf[compsz++] = 0; + outbuf[compsz++] = 0; + /* write a full cluster, to avoid partial reading */ + rounded = ((compsz - 1) | (clsz - 1)) + 1; + written = write_clusters(vol, rl, offs, rounded, outbuf); + if (written != rounded) { +// previously written text has been spoilt, should return a specific error + ntfs_log_error("error writing compressed data\n"); + errno = EIO; + written = -2; + } + } else + if (!fail) + written = 0; + free(outbuf); + } + return (written); +} + +/* + * Free unneeded clusters after compression + * + * This generally requires an empty slot at the end of runlist, + * but we do not want to reallocate the runlist here because + * there are many pointers to it. + * So the empty slot has to be reserved beforehand + * + * Returns zero unless some error occurred (described by errno) + */ + +static int ntfs_compress_free(ntfs_attr *na, runlist_element *rl, + s64 used, s64 reserved) +{ + int freecnt; + int usedcnt; + int res; + s64 freelcn; + s64 freevcn; + int freelength; + BOOL mergeholes; + BOOL beginhole; + ntfs_volume *vol; + runlist_element *freerl; + + res = -1; /* default return */ + vol = na->ni->vol; + freecnt = (reserved - used) >> vol->cluster_size_bits; + usedcnt = (reserved >> vol->cluster_size_bits) - freecnt; + /* skip entries fully used, if any */ + while (rl->length && (rl->length < usedcnt)) { + usedcnt -= rl->length; + rl++; + } + if (rl->length) { + /* + * Splitting the current allocation block requires + * an extra runlist element to create the hole. + * The required entry has been prereserved when + * mapping the runlist. + */ + freelcn = rl->lcn + usedcnt; + freevcn = rl->vcn + usedcnt; + freelength = rl->length - usedcnt; + /* new count of allocated clusters */ + rl->length = usedcnt; /* warning : can be zero */ + if (!((freevcn + freecnt) + & (na->compression_block_clusters - 1))) { + beginhole = !usedcnt && !rl->vcn; + mergeholes = !usedcnt + && rl[0].vcn + && (rl[-1].lcn == LCN_HOLE); + if (mergeholes) { + freerl = rl; + freerl->length = freecnt; + } else + freerl = ++rl; + if ((freelength > 0) + && !mergeholes + && (usedcnt || beginhole)) { + /* + * move the unused part to the end. Doing so, + * the vcn will be out of order. This does + * not harm, the vcn are meaningless now, and + * only the lcn are meaningful for freeing. + */ + /* locate current end */ + while (rl->length) + rl++; + /* new terminator relocated */ + rl[1].vcn = rl->vcn; + rl[1].lcn = LCN_ENOENT; + rl[1].length = 0; + /* hole, currently allocated */ + rl->vcn = freevcn; + rl->lcn = freelcn; + rl->length = freelength; + } + /* free the hole */ + res = ntfs_cluster_free_from_rl(vol,freerl); + if (!res) { + if (mergeholes) { + /* merge with adjacent hole */ + freerl--; + freerl->length += freecnt; + } else { + if (beginhole) + freerl--; + /* mark hole as free */ + freerl->lcn = LCN_HOLE; + freerl->vcn = freevcn; + freerl->length = freecnt; + } + /* and set up the new end */ + freerl[1].lcn = LCN_ENOENT; + freerl[1].vcn = freevcn + freecnt; + freerl[1].length = 0; + } + } else { + ntfs_log_error("Bad end of a compression block set\n"); + errno = EIO; + } + } else { + ntfs_log_error("No cluster to free after compression\n"); + errno = EIO; + } + return (res); +} + +/* + * Read existing data, decompress and append buffer + * Do nothing if something fails + */ + +static int ntfs_read_append(ntfs_attr *na, const runlist_element *rl, + s64 offs, u32 compsz, int pos, + char *outbuf, s64 to_write, const void *b) +{ + int fail = 1; + char *compbuf; + u32 decompsz; + u32 got; + + if (compsz == na->compression_block_size) { + /* if the full block was requested, it was a hole */ + memset(outbuf,0,compsz); + memcpy(&outbuf[pos],b,to_write); + fail = 0; + } else { + compbuf = (char*)ntfs_malloc(compsz); + if (compbuf) { + /* must align to full block for decompression */ + decompsz = ((pos - 1) | (NTFS_SB_SIZE - 1)) + 1; + got = read_clusters(na->ni->vol, rl, offs, + compsz, compbuf); + if ((got == compsz) + && !ntfs_decompress((u8*)outbuf,decompsz, + (u8*)compbuf,compsz)) { + memcpy(&outbuf[pos],b,to_write); + fail = 0; + } + free(compbuf); + } + } + return (fail); +} + +/* + * Flush a full compression block + * + * returns the size actually written (rounded to a full cluster) + * or 0 if could not compress (and written uncompressed) + * or -1 if there were an irrecoverable error (errno set) + */ + +static int ntfs_flush(ntfs_attr *na, runlist_element *rl, s64 offs, + const char *outbuf, int count, BOOL compress) +{ + int rounded; + int written; + int clsz; + + if (compress) { + written = ntfs_comp_set(na, rl, offs, count, outbuf); + if (written == -1) + compress = FALSE; + if ((written >= 0) + && ntfs_compress_free(na,rl,offs + written, + offs + na->compression_block_size)) + written = -1; + } else + written = 0; + if (!compress) { + clsz = 1 << na->ni->vol->cluster_size_bits; + rounded = ((count - 1) | (clsz - 1)) + 1; + written = write_clusters(na->ni->vol, rl, + offs, rounded, outbuf); + if (written != rounded) + written = -1; + } + return (written); +} + +/* + * Write some data to be compressed. + * Compression only occurs when a few clusters (usually 16) are + * full. When this occurs an extra runlist slot may be needed, so + * it has to be reserved beforehand. + * + * Returns the size of uncompressed data written, + * or zero if an error occurred. + * When the returned size is less than requested, new clusters have + * to be allocated before the function is called again. + */ + +s64 ntfs_compressed_pwrite(ntfs_attr *na, runlist_element *wrl, s64 wpos, + s64 offs, s64 to_write, s64 rounded, + const void *b, int compressed_part) +{ + ntfs_volume *vol; + runlist_element *brl; /* entry containing the beginning of block */ + int compression_length; + s64 written; + s64 to_read; + s64 roffs; + s64 got; + s64 start_vcn; + s64 nextblock; + u32 compsz; + char *inbuf; + char *outbuf; + BOOL fail; + BOOL done; + BOOL compress; + + written = 0; /* default return */ + vol = na->ni->vol; + compression_length = na->compression_block_clusters; + compress = FALSE; + done = FALSE; + /* + * Cannot accept writing beyond the current compression set + * because when compression occurs, clusters are freed + * and have to be reallocated. + * (cannot happen with standard fuse 4K buffers) + * Caller has to avoid this situation, or face consequences. + */ + nextblock = ((offs + (wrl->vcn << vol->cluster_size_bits)) + | (na->compression_block_size - 1)) + 1; + if ((offs + to_write + (wrl->vcn << vol->cluster_size_bits)) + >= nextblock) { + /* it is time to compress */ + compress = TRUE; + /* only process what we can */ + to_write = rounded = nextblock + - (offs + (wrl->vcn << vol->cluster_size_bits)); + } + start_vcn = 0; + fail = FALSE; + brl = wrl; + roffs = 0; + /* + * If we are about to compress or we need to decompress + * existing data, we have to process a full set of blocks. + * So relocate the parameters to the beginning of allocation + * containing the first byte of the set of blocks. + */ + if (compress || compressed_part) { + /* find the beginning of block */ + start_vcn = (wrl->vcn + (offs >> vol->cluster_size_bits)) + & -compression_length; + while (brl->vcn && (brl->vcn > start_vcn)) { + /* jumping back a hole means big trouble */ + if (brl->lcn == (LCN)LCN_HOLE) { + ntfs_log_error("jump back over a hole when appending\n"); + fail = TRUE; + errno = EIO; + } + brl--; + offs += brl->length << vol->cluster_size_bits; + } + roffs = (start_vcn - brl->vcn) << vol->cluster_size_bits; + } + if (compressed_part && !fail) { + /* + * The set of compression blocks contains compressed data + * (we are reopening an existing file to append to it) + * Decompress the data and append + */ + compsz = compressed_part << vol->cluster_size_bits; +// improve the needed size + outbuf = (char*)ntfs_malloc(na->compression_block_size); + if (outbuf) { + to_read = offs - roffs; + if (!ntfs_read_append(na, brl, roffs, compsz, + to_read, outbuf, to_write, b)) { + written = ntfs_flush(na, brl, roffs, + outbuf, to_read + to_write, compress); + if (written >= 0) { + written = to_write; + done = TRUE; + } + } + free(outbuf); + } + } else { + if (compress && !fail) { + /* + * we are filling up a block, read the full set of blocks + * and compress it + */ + inbuf = (char*)ntfs_malloc(na->compression_block_size); + if (inbuf) { + to_read = offs - roffs; + if (to_read) + got = read_clusters(vol, brl, roffs, + to_read, inbuf); + else + got = 0; + if (got == to_read) { + memcpy(&inbuf[to_read],b,to_write); + written = ntfs_comp_set(na, brl, roffs, + to_read + to_write, inbuf); + /* + * if compression was not successful, + * only write the part which was requested + */ + if ((written >= 0) + /* free the unused clusters */ + && !ntfs_compress_free(na,brl, + written + roffs, + na->compression_block_size + + roffs)) { + done = TRUE; + written = to_write; + } + } + free(inbuf); + } + } + if (!done) { + /* + * if the compression block is not full, or + * if compression failed for whatever reason, + * write uncompressed + */ + /* check we are not overflowing current allocation */ + if ((wpos + rounded) + > ((wrl->lcn + wrl->length) + << vol->cluster_size_bits)) { + ntfs_log_error("writing on unallocated clusters\n"); + errno = EIO; + } else { + written = ntfs_pwrite(vol->dev, wpos, + rounded, b); + if (written == rounded) + written = to_write; + } + } + } + return (written); +} + +/* + * Close a file written compressed. + * This compresses the last partial compression block of the file. + * An empty runlist slot has to be reserved beforehand. + * + * Returns zero if closing is successful. + */ + +int ntfs_compressed_close(ntfs_attr *na, runlist_element *wrl, s64 offs) +{ + ntfs_volume *vol; + runlist_element *brl; /* entry containing the beginning of block */ + int compression_length; + s64 written; + s64 to_read; + s64 roffs; + s64 got; + s64 start_vcn; + char *inbuf; + BOOL fail; + BOOL done; + + vol = na->ni->vol; + compression_length = na->compression_block_clusters; + done = FALSE; + /* + * There generally is an uncompressed block at end of file, + * read the full block and compress it + */ + inbuf = (char*)ntfs_malloc(na->compression_block_size); + if (inbuf) { + start_vcn = (wrl->vcn + (offs >> vol->cluster_size_bits)) + & -compression_length; + to_read = offs + ((wrl->vcn - start_vcn) << vol->cluster_size_bits); + brl = wrl; + fail = FALSE; + while (brl->vcn && (brl->vcn > start_vcn)) { + if (brl->lcn == (LCN)LCN_HOLE) { + ntfs_log_error("jump back over a hole when closing\n"); + fail = TRUE; + errno = EIO; + } + brl--; + } + if (!fail) { + /* roffs can be an offset from another uncomp block */ + roffs = (start_vcn - brl->vcn) << vol->cluster_size_bits; + if (to_read) { + got = read_clusters(vol, brl, roffs, to_read, + inbuf); + if (got == to_read) { + written = ntfs_comp_set(na, brl, roffs, + to_read, inbuf); + if ((written >= 0) + /* free the unused clusters */ + && !ntfs_compress_free(na,brl, + written + roffs, + na->compression_block_size + roffs)) { + done = TRUE; + } else + /* if compression failed, leave uncompressed */ + if (written == -1) + done = TRUE; + } + } else + done = TRUE; + free(inbuf); + } + } + return (!done); +} diff --git a/libntfs-3g/debug.c b/libntfs-3g/debug.c new file mode 100755 index 0000000..f193483 --- a/dev/null +++ b/libntfs-3g/debug.c @@ -0,0 +1,79 @@ +/** + * debug.c - Debugging output functions. Originated from the Linux-NTFS project. + * + * Copyright (c) 2002-2004 Anton Altaparmakov + * Copyright (c) 2004-2006 Szabolcs Szakacsits + * + * This program/include file 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/include file 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 (in the main directory of the NTFS-3G + * distribution in the file COPYING); if not, write to the Free Software + * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_ERRNO_H +#include +#endif + +#include "types.h" +#include "runlist.h" +#include "debug.h" +#include "logging.h" + +#ifdef DEBUG +/** + * ntfs_debug_runlist_dump - Dump a runlist. + * @rl: + * + * Description... + * + * Returns: + */ +void ntfs_debug_runlist_dump(const runlist_element *rl) +{ + int i = 0; + const char *lcn_str[5] = { "LCN_HOLE ", "LCN_RL_NOT_MAPPED", + "LCN_ENOENT ", "LCN_EINVAL ", + "LCN_unknown " }; + + ntfs_log_debug("NTFS-fs DEBUG: Dumping runlist (values in hex):\n"); + if (!rl) { + ntfs_log_debug("Run list not present.\n"); + return; + } + ntfs_log_debug("VCN LCN Run length\n"); + do { + LCN lcn = (rl + i)->lcn; + + if (lcn < (LCN)0) { + int idx = -lcn - 1; + + if (idx > -LCN_EINVAL - 1) + idx = 4; + ntfs_log_debug("%-16lld %s %-16lld%s\n", + (long long)rl[i].vcn, lcn_str[idx], + (long long)rl[i].length, + rl[i].length ? "" : " (runlist end)"); + } else + ntfs_log_debug("%-16lld %-16lld %-16lld%s\n", + (long long)rl[i].vcn, (long long)rl[i].lcn, + (long long)rl[i].length, + rl[i].length ? "" : " (runlist end)"); + } while (rl[i++].length); +} + +#endif + diff --git a/libntfs-3g/device.c b/libntfs-3g/device.c new file mode 100755 index 0000000..c77d8f9 --- a/dev/null +++ b/libntfs-3g/device.c @@ -0,0 +1,730 @@ +/** + * device.c - Low level device io functions. Originated from the Linux-NTFS project. + * + * Copyright (c) 2004-2006 Anton Altaparmakov + * Copyright (c) 2004-2006 Szabolcs Szakacsits + * + * This program/include file 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/include file 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 (in the main directory of the NTFS-3G + * distribution in the file COPYING); if not, write to the Free Software + * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_ERRNO_H +#include +#endif +#ifdef HAVE_STDIO_H +#include +#endif +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_STAT_H +#include +#endif +#ifdef HAVE_FCNTL_H +#include +#endif +#ifdef HAVE_SYS_IOCTL_H +#include +#endif +#ifdef HAVE_SYS_PARAM_H +#include +#endif +#ifdef HAVE_SYS_MOUNT_H +#include +#endif +#ifdef HAVE_LINUX_FD_H +#include +#endif +#ifdef HAVE_LINUX_HDREG_H +#include +#endif + +#include "types.h" +#include "mst.h" +#include "debug.h" +#include "device.h" +#include "logging.h" +#include "misc.h" + +#if defined(linux) && defined(_IO) && !defined(BLKGETSIZE) +#define BLKGETSIZE _IO(0x12,96) /* Get device size in 512-byte blocks. */ +#endif +#if defined(linux) && defined(_IOR) && !defined(BLKGETSIZE64) +#define BLKGETSIZE64 _IOR(0x12,114,size_t) /* Get device size in bytes. */ +#endif +#if defined(linux) && !defined(HDIO_GETGEO) +#define HDIO_GETGEO 0x0301 /* Get device geometry. */ +#endif +#if defined(linux) && defined(_IO) && !defined(BLKSSZGET) +# define BLKSSZGET _IO(0x12,104) /* Get device sector size in bytes. */ +#endif +#if defined(linux) && defined(_IO) && !defined(BLKBSZSET) +# define BLKBSZSET _IOW(0x12,113,size_t) /* Set device block size in bytes. */ +#endif + +/** + * ntfs_device_alloc - allocate an ntfs device structure and pre-initialize it + * @name: name of the device (must be present) + * @state: initial device state (usually zero) + * @dops: ntfs device operations to use with the device (must be present) + * @priv_data: pointer to private data (optional) + * + * Allocate an ntfs device structure and pre-initialize it with the user- + * specified device operations @dops, device state @state, device name @name, + * and optional private data @priv_data. + * + * Note, @name is copied and can hence be freed after this functions returns. + * + * On success return a pointer to the allocated ntfs device structure and on + * error return NULL with errno set to the error code returned by ntfs_malloc(). + */ +struct ntfs_device *ntfs_device_alloc(const char *name, const long state, + struct ntfs_device_operations *dops, void *priv_data) +{ + struct ntfs_device *dev; + + if (!name) { + errno = EINVAL; + return NULL; + } + + dev = ntfs_malloc(sizeof(struct ntfs_device)); + if (dev) { + if (!(dev->d_name = strdup(name))) { + int eo = errno; + free(dev); + errno = eo; + return NULL; + } + dev->d_ops = dops; + dev->d_state = state; + dev->d_private = priv_data; + } + return dev; +} + +/** + * ntfs_device_free - free an ntfs device structure + * @dev: ntfs device structure to free + * + * Free the ntfs device structure @dev. + * + * Return 0 on success or -1 on error with errno set to the error code. The + * following error codes are defined: + * EINVAL Invalid pointer @dev. + * EBUSY Device is still open. Close it before freeing it! + */ +int ntfs_device_free(struct ntfs_device *dev) +{ + if (!dev) { + errno = EINVAL; + return -1; + } + if (NDevOpen(dev)) { + errno = EBUSY; + return -1; + } + free(dev->d_name); + free(dev); + return 0; +} + +/** + * ntfs_pread - positioned read from disk + * @dev: device to read from + * @pos: position in device to read from + * @count: number of bytes to read + * @b: output data buffer + * + * This function will read @count bytes from device @dev at position @pos into + * the data buffer @b. + * + * On success, return the number of successfully read bytes. If this number is + * lower than @count this means that we have either reached end of file or + * encountered an error during the read so that the read is partial. 0 means + * end of file or nothing to read (@count is 0). + * + * On error and nothing has been read, return -1 with errno set appropriately + * to the return code of either seek, read, or set to EINVAL in case of + * invalid arguments. + */ +s64 ntfs_pread(struct ntfs_device *dev, const s64 pos, s64 count, void *b) +{ + s64 br, total; + struct ntfs_device_operations *dops; + + ntfs_log_trace("pos %lld, count %lld\n",(long long)pos,(long long)count); + + if (!b || count < 0 || pos < 0) { + errno = EINVAL; + return -1; + } + if (!count) + return 0; + + dops = dev->d_ops; + + for (total = 0; count; count -= br, total += br) { + br = dops->pread(dev, (char*)b + total, count, pos + total); + /* If everything ok, continue. */ + if (br > 0) + continue; + /* If EOF or error return number of bytes read. */ + if (!br || total) + return total; + /* Nothing read and error, return error status. */ + return br; + } + /* Finally, return the number of bytes read. */ + return total; +} + +/** + * ntfs_pwrite - positioned write to disk + * @dev: device to write to + * @pos: position in file descriptor to write to + * @count: number of bytes to write + * @b: data buffer to write to disk + * + * This function will write @count bytes from data buffer @b to the device @dev + * at position @pos. + * + * On success, return the number of successfully written bytes. If this number + * is lower than @count this means that the write has been interrupted in + * flight or that an error was encountered during the write so that the write + * is partial. 0 means nothing was written (also return 0 when @count is 0). + * + * On error and nothing has been written, return -1 with errno set + * appropriately to the return code of either seek, write, or set + * to EINVAL in case of invalid arguments. + */ +s64 ntfs_pwrite(struct ntfs_device *dev, const s64 pos, s64 count, + const void *b) +{ + s64 written, total, ret = -1; + struct ntfs_device_operations *dops; + + ntfs_log_trace("pos %lld, count %lld\n",(long long)pos,(long long)count); + + if (!b || count < 0 || pos < 0) { + errno = EINVAL; + goto out; + } + if (!count) + return 0; + if (NDevReadOnly(dev)) { + errno = EROFS; + goto out; + } + + dops = dev->d_ops; + + NDevSetDirty(dev); + for (total = 0; count; count -= written, total += written) { + written = dops->pwrite(dev, (const char*)b + total, count, + pos + total); + /* If everything ok, continue. */ + if (written > 0) + continue; + /* + * If nothing written or error return number of bytes written. + */ + if (!written || total) + break; + /* Nothing written and error, return error status. */ + total = written; + break; + } + ret = total; +out: + return ret; +} + +/** + * ntfs_mst_pread - multi sector transfer (mst) positioned read + * @dev: device to read from + * @pos: position in file descriptor to read from + * @count: number of blocks to read + * @bksize: size of each block that needs mst deprotecting + * @b: output data buffer + * + * Multi sector transfer (mst) positioned read. This function will read @count + * blocks of size @bksize bytes each from device @dev at position @pos into the + * the data buffer @b. + * + * On success, return the number of successfully read blocks. If this number is + * lower than @count this means that we have reached end of file, that the read + * was interrupted, or that an error was encountered during the read so that + * the read is partial. 0 means end of file or nothing was read (also return 0 + * when @count or @bksize are 0). + * + * On error and nothing was read, return -1 with errno set appropriately to the + * return code of either seek, read, or set to EINVAL in case of invalid + * arguments. + * + * NOTE: If an incomplete multi sector transfer has been detected the magic + * will have been changed to magic_BAAD but no error will be returned. Thus it + * is possible that we return count blocks as being read but that any number + * (between zero and count!) of these blocks is actually subject to a multi + * sector transfer error. This should be detected by the caller by checking for + * the magic being "BAAD". + */ +s64 ntfs_mst_pread(struct ntfs_device *dev, const s64 pos, s64 count, + const u32 bksize, void *b) +{ + s64 br, i; + + if (bksize & (bksize - 1) || bksize % NTFS_BLOCK_SIZE) { + errno = EINVAL; + return -1; + } + /* Do the read. */ + br = ntfs_pread(dev, pos, count * bksize, b); + if (br < 0) + return br; + /* + * Apply fixups to successfully read data, disregarding any errors + * returned from the MST fixup function. This is because we want to + * fixup everything possible and we rely on the fact that the "BAAD" + * magic will be detected later on. + */ + count = br / bksize; + for (i = 0; i < count; ++i) + ntfs_mst_post_read_fixup((NTFS_RECORD*) + ((u8*)b + i * bksize), bksize); + /* Finally, return the number of complete blocks read. */ + return count; +} + +/** + * ntfs_mst_pwrite - multi sector transfer (mst) positioned write + * @dev: device to write to + * @pos: position in file descriptor to write to + * @count: number of blocks to write + * @bksize: size of each block that needs mst protecting + * @b: data buffer to write to disk + * + * Multi sector transfer (mst) positioned write. This function will write + * @count blocks of size @bksize bytes each from data buffer @b to the device + * @dev at position @pos. + * + * On success, return the number of successfully written blocks. If this number + * is lower than @count this means that the write has been interrupted or that + * an error was encountered during the write so that the write is partial. 0 + * means nothing was written (also return 0 when @count or @bksize are 0). + * + * On error and nothing has been written, return -1 with errno set + * appropriately to the return code of either seek, write, or set + * to EINVAL in case of invalid arguments. + * + * NOTE: We mst protect the data, write it, then mst deprotect it using a quick + * deprotect algorithm (no checking). This saves us from making a copy before + * the write and at the same time causes the usn to be incremented in the + * buffer. This conceptually fits in better with the idea that cached data is + * always deprotected and protection is performed when the data is actually + * going to hit the disk and the cache is immediately deprotected again + * simulating an mst read on the written data. This way cache coherency is + * achieved. + */ +s64 ntfs_mst_pwrite(struct ntfs_device *dev, const s64 pos, s64 count, + const u32 bksize, void *b) +{ + s64 written, i; + + if (count < 0 || bksize % NTFS_BLOCK_SIZE) { + errno = EINVAL; + return -1; + } + if (!count) + return 0; + /* Prepare data for writing. */ + for (i = 0; i < count; ++i) { + int err; + + err = ntfs_mst_pre_write_fixup((NTFS_RECORD*) + ((u8*)b + i * bksize), bksize); + if (err < 0) { + /* Abort write at this position. */ + if (!i) + return err; + count = i; + break; + } + } + /* Write the prepared data. */ + written = ntfs_pwrite(dev, pos, count * bksize, b); + /* Quickly deprotect the data again. */ + for (i = 0; i < count; ++i) + ntfs_mst_post_write_fixup((NTFS_RECORD*)((u8*)b + i * bksize)); + if (written <= 0) + return written; + /* Finally, return the number of complete blocks written. */ + return written / bksize; +} + +/** + * ntfs_cluster_read - read ntfs clusters + * @vol: volume to read from + * @lcn: starting logical cluster number + * @count: number of clusters to read + * @b: output data buffer + * + * Read @count ntfs clusters starting at logical cluster number @lcn from + * volume @vol into buffer @b. Return number of clusters read or -1 on error, + * with errno set to the error code. + */ +s64 ntfs_cluster_read(const ntfs_volume *vol, const s64 lcn, const s64 count, + void *b) +{ + s64 br; + + if (!vol || lcn < 0 || count < 0) { + errno = EINVAL; + return -1; + } + if (vol->nr_clusters < lcn + count) { + errno = ESPIPE; + ntfs_log_perror("Trying to read outside of volume " + "(%lld < %lld)", (long long)vol->nr_clusters, + (long long)lcn + count); + return -1; + } + br = ntfs_pread(vol->dev, lcn << vol->cluster_size_bits, + count << vol->cluster_size_bits, b); + if (br < 0) { + ntfs_log_perror("Error reading cluster(s)"); + return br; + } + return br >> vol->cluster_size_bits; +} + +/** + * ntfs_cluster_write - write ntfs clusters + * @vol: volume to write to + * @lcn: starting logical cluster number + * @count: number of clusters to write + * @b: data buffer to write to disk + * + * Write @count ntfs clusters starting at logical cluster number @lcn from + * buffer @b to volume @vol. Return the number of clusters written or -1 on + * error, with errno set to the error code. + */ +s64 ntfs_cluster_write(const ntfs_volume *vol, const s64 lcn, + const s64 count, const void *b) +{ + s64 bw; + + if (!vol || lcn < 0 || count < 0) { + errno = EINVAL; + return -1; + } + if (vol->nr_clusters < lcn + count) { + errno = ESPIPE; + ntfs_log_perror("Trying to write outside of volume " + "(%lld < %lld)", (long long)vol->nr_clusters, + (long long)lcn + count); + return -1; + } + if (!NVolReadOnly(vol)) + bw = ntfs_pwrite(vol->dev, lcn << vol->cluster_size_bits, + count << vol->cluster_size_bits, b); + else + bw = count << vol->cluster_size_bits; + if (bw < 0) { + ntfs_log_perror("Error writing cluster(s)"); + return bw; + } + return bw >> vol->cluster_size_bits; +} + +/** + * ntfs_device_offset_valid - test if a device offset is valid + * @dev: open device + * @ofs: offset to test for validity + * + * Test if the offset @ofs is an existing location on the device described + * by the open device structure @dev. + * + * Return 0 if it is valid and -1 if it is not valid. + */ +static int ntfs_device_offset_valid(struct ntfs_device *dev, s64 ofs) +{ + char ch; + + if (dev->d_ops->seek(dev, ofs, SEEK_SET) >= 0 && + dev->d_ops->read(dev, &ch, 1) == 1) + return 0; + return -1; +} + +/** + * ntfs_device_size_get - return the size of a device in blocks + * @dev: open device + * @block_size: block size in bytes in which to return the result + * + * Return the number of @block_size sized blocks in the device described by the + * open device @dev. + * + * Adapted from e2fsutils-1.19, Copyright (C) 1995 Theodore Ts'o. + * + * On error return -1 with errno set to the error code. + */ +s64 ntfs_device_size_get(struct ntfs_device *dev, int block_size) +{ + s64 high, low; + + if (!dev || block_size <= 0 || (block_size - 1) & block_size) { + errno = EINVAL; + return -1; + } +#ifdef BLKGETSIZE64 + { u64 size; + + if (dev->d_ops->ioctl(dev, BLKGETSIZE64, &size) >= 0) { + ntfs_log_debug("BLKGETSIZE64 nr bytes = %llu (0x%llx)\n", + (unsigned long long)size, + (unsigned long long)size); + return (s64)size / block_size; + } + } +#endif +#ifdef BLKGETSIZE + { unsigned long size; + + if (dev->d_ops->ioctl(dev, BLKGETSIZE, &size) >= 0) { + ntfs_log_debug("BLKGETSIZE nr 512 byte blocks = %lu (0x%lx)\n", + size, size); + return (s64)size * 512 / block_size; + } + } +#endif +#ifdef FDGETPRM + { struct floppy_struct this_floppy; + + if (dev->d_ops->ioctl(dev, FDGETPRM, &this_floppy) >= 0) { + ntfs_log_debug("FDGETPRM nr 512 byte blocks = %lu (0x%lx)\n", + (unsigned long)this_floppy.size, + (unsigned long)this_floppy.size); + return (s64)this_floppy.size * 512 / block_size; + } + } +#endif + /* + * We couldn't figure it out by using a specialized ioctl, + * so do binary search to find the size of the device. + */ + low = 0LL; + for (high = 1024LL; !ntfs_device_offset_valid(dev, high); high <<= 1) + low = high; + while (low < high - 1LL) { + const s64 mid = (low + high) / 2; + + if (!ntfs_device_offset_valid(dev, mid)) + low = mid; + else + high = mid; + } + dev->d_ops->seek(dev, 0LL, SEEK_SET); + return (low + 1LL) / block_size; +} + +/** + * ntfs_device_partition_start_sector_get - get starting sector of a partition + * @dev: open device + * + * On success, return the starting sector of the partition @dev in the parent + * block device of @dev. On error return -1 with errno set to the error code. + * + * The following error codes are defined: + * EINVAL Input parameter error + * EOPNOTSUPP System does not support HDIO_GETGEO ioctl + * ENOTTY @dev is a file or a device not supporting HDIO_GETGEO + */ +s64 ntfs_device_partition_start_sector_get(struct ntfs_device *dev) +{ + if (!dev) { + errno = EINVAL; + return -1; + } +#ifdef HDIO_GETGEO + { struct hd_geometry geo; + + if (!dev->d_ops->ioctl(dev, HDIO_GETGEO, &geo)) { + ntfs_log_debug("HDIO_GETGEO start_sect = %lu (0x%lx)\n", + geo.start, geo.start); + return geo.start; + } + } +#else + errno = EOPNOTSUPP; +#endif + return -1; +} + +/** + * ntfs_device_heads_get - get number of heads of device + * @dev: open device + * + * On success, return the number of heads on the device @dev. On error return + * -1 with errno set to the error code. + * + * The following error codes are defined: + * EINVAL Input parameter error + * EOPNOTSUPP System does not support HDIO_GETGEO ioctl + * ENOTTY @dev is a file or a device not supporting HDIO_GETGEO + */ +int ntfs_device_heads_get(struct ntfs_device *dev) +{ + if (!dev) { + errno = EINVAL; + return -1; + } +#ifdef HDIO_GETGEO + { struct hd_geometry geo; + + if (!dev->d_ops->ioctl(dev, HDIO_GETGEO, &geo)) { + ntfs_log_debug("HDIO_GETGEO heads = %u (0x%x)\n", + (unsigned)geo.heads, + (unsigned)geo.heads); + return geo.heads; + } + } +#else + errno = EOPNOTSUPP; +#endif + return -1; +} + +/** + * ntfs_device_sectors_per_track_get - get number of sectors per track of device + * @dev: open device + * + * On success, return the number of sectors per track on the device @dev. On + * error return -1 with errno set to the error code. + * + * The following error codes are defined: + * EINVAL Input parameter error + * EOPNOTSUPP System does not support HDIO_GETGEO ioctl + * ENOTTY @dev is a file or a device not supporting HDIO_GETGEO + */ +int ntfs_device_sectors_per_track_get(struct ntfs_device *dev) +{ + if (!dev) { + errno = EINVAL; + return -1; + } +#ifdef HDIO_GETGEO + { struct hd_geometry geo; + + if (!dev->d_ops->ioctl(dev, HDIO_GETGEO, &geo)) { + ntfs_log_debug("HDIO_GETGEO sectors_per_track = %u (0x%x)\n", + (unsigned)geo.sectors, + (unsigned)geo.sectors); + return geo.sectors; + } + } +#else + errno = EOPNOTSUPP; +#endif + return -1; +} + +/** + * ntfs_device_sector_size_get - get sector size of a device + * @dev: open device + * + * On success, return the sector size in bytes of the device @dev. + * On error return -1 with errno set to the error code. + * + * The following error codes are defined: + * EINVAL Input parameter error + * EOPNOTSUPP System does not support BLKSSZGET ioctl + * ENOTTY @dev is a file or a device not supporting BLKSSZGET + */ +int ntfs_device_sector_size_get(struct ntfs_device *dev) +{ + if (!dev) { + errno = EINVAL; + return -1; + } +#ifdef BLKSSZGET + { + int sect_size = 0; + + if (!dev->d_ops->ioctl(dev, BLKSSZGET, §_size)) { + ntfs_log_debug("BLKSSZGET sector size = %d bytes\n", + sect_size); + return sect_size; + } + } +#else + errno = EOPNOTSUPP; +#endif + return -1; +} + +/** + * ntfs_device_block_size_set - set block size of a device + * @dev: open device + * @block_size: block size to set @dev to + * + * On success, return 0. + * On error return -1 with errno set to the error code. + * + * The following error codes are defined: + * EINVAL Input parameter error + * EOPNOTSUPP System does not support BLKBSZSET ioctl + * ENOTTY @dev is a file or a device not supporting BLKBSZSET + */ +int ntfs_device_block_size_set(struct ntfs_device *dev, + int block_size __attribute__((unused))) +{ + if (!dev) { + errno = EINVAL; + return -1; + } +#ifdef BLKBSZSET + { + size_t s_block_size = block_size; + if (!dev->d_ops->ioctl(dev, BLKBSZSET, &s_block_size)) { + ntfs_log_debug("Used BLKBSZSET to set block size to " + "%d bytes.\n", block_size); + return 0; + } + /* If not a block device, pretend it was successful. */ + if (!NDevBlock(dev)) + return 0; + } +#else + /* If not a block device, pretend it was successful. */ + if (!NDevBlock(dev)) + return 0; + errno = EOPNOTSUPP; +#endif + return -1; +} diff --git a/libntfs-3g/dir.c b/libntfs-3g/dir.c new file mode 100755 index 0000000..9c82765 --- a/dev/null +++ b/libntfs-3g/dir.c @@ -0,0 +1,2582 @@ +/** + * dir.c - Directory handling code. Originated from the Linux-NTFS project. + * + * Copyright (c) 2002-2005 Anton Altaparmakov + * Copyright (c) 2004-2005 Richard Russon + * Copyright (c) 2004-2008 Szabolcs Szakacsits + * Copyright (c) 2005-2007 Yura Pakhuchiy + * Copyright (c) 2008-2010 Jean-Pierre Andre + * + * This program/include file 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/include file 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 (in the main directory of the NTFS-3G + * distribution in the file COPYING); if not, write to the Free Software + * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_ERRNO_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_SYS_STAT_H +#include +#endif + +#ifdef HAVE_SYS_SYSMACROS_H +#include +#endif + +#include "param.h" +#include "types.h" +#include "debug.h" +#include "attrib.h" +#include "inode.h" +#include "dir.h" +#include "volume.h" +#include "mft.h" +#include "index.h" +#include "ntfstime.h" +#include "lcnalloc.h" +#include "logging.h" +#include "cache.h" +#include "misc.h" +#include "security.h" +#include "reparse.h" +#include "object_id.h" + +#ifdef HAVE_SETXATTR +#include +#endif + +/* + * The little endian Unicode strings "$I30", "$SII", "$SDH", "$O" + * and "$Q" as global constants. + */ +ntfschar NTFS_INDEX_I30[5] = { const_cpu_to_le16('$'), const_cpu_to_le16('I'), + const_cpu_to_le16('3'), const_cpu_to_le16('0'), + const_cpu_to_le16('\0') }; +ntfschar NTFS_INDEX_SII[5] = { const_cpu_to_le16('$'), const_cpu_to_le16('S'), + const_cpu_to_le16('I'), const_cpu_to_le16('I'), + const_cpu_to_le16('\0') }; +ntfschar NTFS_INDEX_SDH[5] = { const_cpu_to_le16('$'), const_cpu_to_le16('S'), + const_cpu_to_le16('D'), const_cpu_to_le16('H'), + const_cpu_to_le16('\0') }; +ntfschar NTFS_INDEX_O[3] = { const_cpu_to_le16('$'), const_cpu_to_le16('O'), + const_cpu_to_le16('\0') }; +ntfschar NTFS_INDEX_Q[3] = { const_cpu_to_le16('$'), const_cpu_to_le16('Q'), + const_cpu_to_le16('\0') }; +ntfschar NTFS_INDEX_R[3] = { const_cpu_to_le16('$'), const_cpu_to_le16('R'), + const_cpu_to_le16('\0') }; + +#if CACHE_INODE_SIZE + +/* + * Pathname hashing + * + * Based on first char and second char (which may be '\0') + */ + +int ntfs_dir_inode_hash(const struct CACHED_GENERIC *cached) +{ + const char *path; + const unsigned char *name; + + path = (const char*)cached->variable; + if (!path) { + ntfs_log_error("Bad inode cache entry\n"); + return (-1); + } + name = (const unsigned char*)strrchr(path,'/'); + if (!name) + name = (const unsigned char*)path; + return (((name[0] << 1) + name[1] + strlen((const char*)name)) + % (2*CACHE_INODE_SIZE)); +} + +/* + * Pathname comparing for entering/fetching from cache + */ + +static int inode_cache_compare(const struct CACHED_GENERIC *cached, + const struct CACHED_GENERIC *wanted) +{ + return (!cached->variable + || strcmp(cached->variable, wanted->variable)); +} + +/* + * Pathname comparing for invalidating entries in cache + * + * A partial path is compared in order to invalidate all paths + * related to a renamed directory + * inode numbers are also checked, as deleting a long name may + * imply deleting a short name and conversely + * + * Only use associated with a CACHE_NOHASH flag + */ + +static int inode_cache_inv_compare(const struct CACHED_GENERIC *cached, + const struct CACHED_GENERIC *wanted) +{ + int len; + BOOL different; + const struct CACHED_INODE *w; + const struct CACHED_INODE *c; + + w = (const struct CACHED_INODE*)wanted; + c = (const struct CACHED_INODE*)cached; + if (w->pathname) { + len = strlen(w->pathname); + different = !cached->variable + || ((w->inum != MREF(c->inum)) + && (strncmp(c->pathname, w->pathname, len) + || ((c->pathname[len] != '\0') + && (c->pathname[len] != '/')))); + } else + different = !c->pathname + || (w->inum != MREF(c->inum)); + return (different); +} + +#endif + +#if CACHE_LOOKUP_SIZE + +/* + * File name comparing for entering/fetching from lookup cache + */ + +static int lookup_cache_compare(const struct CACHED_GENERIC *cached, + const struct CACHED_GENERIC *wanted) +{ + const struct CACHED_LOOKUP *c = (const struct CACHED_LOOKUP*) cached; + const struct CACHED_LOOKUP *w = (const struct CACHED_LOOKUP*) wanted; + return (!c->name + || (c->parent != w->parent) + || (c->namesize != w->namesize) + || memcmp(c->name, w->name, c->namesize)); +} + +/* + * Inode number comparing for invalidating lookup cache + * + * All entries with designated inode number are invalidated + * + * Only use associated with a CACHE_NOHASH flag + */ + +static int lookup_cache_inv_compare(const struct CACHED_GENERIC *cached, + const struct CACHED_GENERIC *wanted) +{ + const struct CACHED_LOOKUP *c = (const struct CACHED_LOOKUP*) cached; + const struct CACHED_LOOKUP *w = (const struct CACHED_LOOKUP*) wanted; + return (!c->name + || (c->parent != w->parent) + || (MREF(c->inum) != MREF(w->inum))); +} + +/* + * Lookup hashing + * + * Based on first, second and and last char + */ + +int ntfs_dir_lookup_hash(const struct CACHED_GENERIC *cached) +{ + const unsigned char *name; + int count; + unsigned int val; + + name = (const unsigned char*)cached->variable; + count = cached->varsize; + if (!name || !count) { + ntfs_log_error("Bad lookup cache entry\n"); + return (-1); + } + val = (name[0] << 2) + (name[1] << 1) + name[count - 1] + count; + return (val % (2*CACHE_LOOKUP_SIZE)); +} + +#endif + +/** + * ntfs_inode_lookup_by_name - find an inode in a directory given its name + * @dir_ni: ntfs inode of the directory in which to search for the name + * @uname: Unicode name for which to search in the directory + * @uname_len: length of the name @uname in Unicode characters + * + * Look for an inode with name @uname in the directory with inode @dir_ni. + * ntfs_inode_lookup_by_name() walks the contents of the directory looking for + * the Unicode name. If the name is found in the directory, the corresponding + * inode number (>= 0) is returned as a mft reference in cpu format, i.e. it + * is a 64-bit number containing the sequence number. + * + * On error, return -1 with errno set to the error code. If the inode is is not + * found errno is ENOENT. + * + * Note, @uname_len does not include the (optional) terminating NULL character. + * + * Note, we look for a case sensitive match first but we also look for a case + * insensitive match at the same time. If we find a case insensitive match, we + * save that for the case that we don't find an exact match, where we return + * the mft reference of the case insensitive match. + * + * If the volume is mounted with the case sensitive flag set, then we only + * allow exact matches. + */ +u64 ntfs_inode_lookup_by_name(ntfs_inode *dir_ni, + const ntfschar *uname, const int uname_len) +{ + VCN vcn; + u64 mref = 0; + s64 br; + ntfs_volume *vol = dir_ni->vol; + ntfs_attr_search_ctx *ctx; + INDEX_ROOT *ir; + INDEX_ENTRY *ie; + INDEX_ALLOCATION *ia; + u8 *index_end; + ntfs_attr *ia_na; + int eo, rc; + u32 index_block_size, index_vcn_size; + u8 index_vcn_size_bits; + + ntfs_log_trace("Entering\n"); + + if (!dir_ni || !dir_ni->mrec || !uname || uname_len <= 0) { + errno = EINVAL; + return -1; + } + + ctx = ntfs_attr_get_search_ctx(dir_ni, NULL); + if (!ctx) + return -1; + + /* Find the index root attribute in the mft record. */ + if (ntfs_attr_lookup(AT_INDEX_ROOT, NTFS_INDEX_I30, 4, CASE_SENSITIVE, 0, NULL, + 0, ctx)) { + ntfs_log_perror("Index root attribute missing in directory inode " + "%lld", (unsigned long long)dir_ni->mft_no); + goto put_err_out; + } + /* Get to the index root value. */ + ir = (INDEX_ROOT*)((u8*)ctx->attr + + le16_to_cpu(ctx->attr->value_offset)); + index_block_size = le32_to_cpu(ir->index_block_size); + if (index_block_size < NTFS_BLOCK_SIZE || + index_block_size & (index_block_size - 1)) { + ntfs_log_error("Index block size %u is invalid.\n", + (unsigned)index_block_size); + goto put_err_out; + } + index_end = (u8*)&ir->index + le32_to_cpu(ir->index.index_length); + /* The first index entry. */ + ie = (INDEX_ENTRY*)((u8*)&ir->index + + le32_to_cpu(ir->index.entries_offset)); + /* + * Loop until we exceed valid memory (corruption case) or until we + * reach the last entry. + */ + for (;; ie = (INDEX_ENTRY*)((u8*)ie + le16_to_cpu(ie->length))) { + /* Bounds checks. */ + if ((u8*)ie < (u8*)ctx->mrec || (u8*)ie + + sizeof(INDEX_ENTRY_HEADER) > index_end || + (u8*)ie + le16_to_cpu(ie->key_length) > + index_end) { + ntfs_log_error("Index entry out of bounds in inode %lld" + "\n", (unsigned long long)dir_ni->mft_no); + goto put_err_out; + } + /* + * The last entry cannot contain a name. It can however contain + * a pointer to a child node in the B+tree so we just break out. + */ + if (ie->ie_flags & INDEX_ENTRY_END) + break; + + if (!le16_to_cpu(ie->length)) { + ntfs_log_error("Zero length index entry in inode %lld" + "\n", (unsigned long long)dir_ni->mft_no); + goto put_err_out; + } + /* + * Not a perfect match, need to do full blown collation so we + * know which way in the B+tree we have to go. + */ + rc = ntfs_names_full_collate(uname, uname_len, + (ntfschar*)&ie->key.file_name.file_name, + ie->key.file_name.file_name_length, + CASE_SENSITIVE, vol->upcase, vol->upcase_len); + /* + * If uname collates before the name of the current entry, there + * is definitely no such name in this index but we might need to + * descend into the B+tree so we just break out of the loop. + */ + if (rc == -1) + break; + /* The names are not equal, continue the search. */ + if (rc) + continue; + /* + * Perfect match, this will never happen as the + * ntfs_are_names_equal() call will have gotten a match but we + * still treat it correctly. + */ + mref = le64_to_cpu(ie->indexed_file); + ntfs_attr_put_search_ctx(ctx); + return mref; + } + /* + * We have finished with this index without success. Check for the + * presence of a child node and if not present return error code + * ENOENT, unless we have got the mft reference of a matching name + * cached in mref in which case return mref. + */ + if (!(ie->ie_flags & INDEX_ENTRY_NODE)) { + ntfs_attr_put_search_ctx(ctx); + if (mref) + return mref; + ntfs_log_debug("Entry not found.\n"); + errno = ENOENT; + return -1; + } /* Child node present, descend into it. */ + + /* Open the index allocation attribute. */ + ia_na = ntfs_attr_open(dir_ni, AT_INDEX_ALLOCATION, NTFS_INDEX_I30, 4); + if (!ia_na) { + ntfs_log_perror("Failed to open index allocation (inode %lld)", + (unsigned long long)dir_ni->mft_no); + goto put_err_out; + } + + /* Allocate a buffer for the current index block. */ + ia = ntfs_malloc(index_block_size); + if (!ia) { + ntfs_attr_close(ia_na); + goto put_err_out; + } + + /* Determine the size of a vcn in the directory index. */ + if (vol->cluster_size <= index_block_size) { + index_vcn_size = vol->cluster_size; + index_vcn_size_bits = vol->cluster_size_bits; + } else { + index_vcn_size = vol->sector_size; + index_vcn_size_bits = vol->sector_size_bits; + } + + /* Get the starting vcn of the index_block holding the child node. */ + vcn = sle64_to_cpup((u8*)ie + le16_to_cpu(ie->length) - 8); + +descend_into_child_node: + + /* Read the index block starting at vcn. */ + br = ntfs_attr_mst_pread(ia_na, vcn << index_vcn_size_bits, 1, + index_block_size, ia); + if (br != 1) { + if (br != -1) + errno = EIO; + ntfs_log_perror("Failed to read vcn 0x%llx", + (unsigned long long)vcn); + goto close_err_out; + } + + if (sle64_to_cpu(ia->index_block_vcn) != vcn) { + ntfs_log_error("Actual VCN (0x%llx) of index buffer is different " + "from expected VCN (0x%llx).\n", + (long long)sle64_to_cpu(ia->index_block_vcn), + (long long)vcn); + errno = EIO; + goto close_err_out; + } + if (le32_to_cpu(ia->index.allocated_size) + 0x18 != index_block_size) { + ntfs_log_error("Index buffer (VCN 0x%llx) of directory inode 0x%llx " + "has a size (%u) differing from the directory " + "specified size (%u).\n", (long long)vcn, + (unsigned long long)dir_ni->mft_no, + (unsigned) le32_to_cpu(ia->index.allocated_size) + 0x18, + (unsigned)index_block_size); + errno = EIO; + goto close_err_out; + } + index_end = (u8*)&ia->index + le32_to_cpu(ia->index.index_length); + if (index_end > (u8*)ia + index_block_size) { + ntfs_log_error("Size of index buffer (VCN 0x%llx) of directory inode " + "0x%llx exceeds maximum size.\n", + (long long)vcn, (unsigned long long)dir_ni->mft_no); + errno = EIO; + goto close_err_out; + } + + /* The first index entry. */ + ie = (INDEX_ENTRY*)((u8*)&ia->index + + le32_to_cpu(ia->index.entries_offset)); + /* + * Iterate similar to above big loop but applied to index buffer, thus + * loop until we exceed valid memory (corruption case) or until we + * reach the last entry. + */ + for (;; ie = (INDEX_ENTRY*)((u8*)ie + le16_to_cpu(ie->length))) { + /* Bounds check. */ + if ((u8*)ie < (u8*)ia || (u8*)ie + + sizeof(INDEX_ENTRY_HEADER) > index_end || + (u8*)ie + le16_to_cpu(ie->key_length) > + index_end) { + ntfs_log_error("Index entry out of bounds in directory " + "inode %lld.\n", + (unsigned long long)dir_ni->mft_no); + errno = EIO; + goto close_err_out; + } + /* + * The last entry cannot contain a name. It can however contain + * a pointer to a child node in the B+tree so we just break out. + */ + if (ie->ie_flags & INDEX_ENTRY_END) + break; + + if (!le16_to_cpu(ie->length)) { + errno = EIO; + ntfs_log_error("Zero length index entry in inode %lld" + "\n", (unsigned long long)dir_ni->mft_no); + goto close_err_out; + } + /* + * Not a perfect match, need to do full blown collation so we + * know which way in the B+tree we have to go. + */ + rc = ntfs_names_full_collate(uname, uname_len, + (ntfschar*)&ie->key.file_name.file_name, + ie->key.file_name.file_name_length, + CASE_SENSITIVE, vol->upcase, vol->upcase_len); + /* + * If uname collates before the name of the current entry, there + * is definitely no such name in this index but we might need to + * descend into the B+tree so we just break out of the loop. + */ + if (rc == -1) + break; + /* The names are not equal, continue the search. */ + if (rc) + continue; + mref = le64_to_cpu(ie->indexed_file); + free(ia); + ntfs_attr_close(ia_na); + ntfs_attr_put_search_ctx(ctx); + return mref; + } + /* + * We have finished with this index buffer without success. Check for + * the presence of a child node. + */ + if (ie->ie_flags & INDEX_ENTRY_NODE) { + if ((ia->index.ih_flags & NODE_MASK) == LEAF_NODE) { + ntfs_log_error("Index entry with child node found in a leaf " + "node in directory inode %lld.\n", + (unsigned long long)dir_ni->mft_no); + errno = EIO; + goto close_err_out; + } + /* Child node present, descend into it. */ + vcn = sle64_to_cpup((u8*)ie + le16_to_cpu(ie->length) - 8); + if (vcn >= 0) + goto descend_into_child_node; + ntfs_log_error("Negative child node vcn in directory inode " + "0x%llx.\n", (unsigned long long)dir_ni->mft_no); + errno = EIO; + goto close_err_out; + } + free(ia); + ntfs_attr_close(ia_na); + ntfs_attr_put_search_ctx(ctx); + /* + * No child node present, return error code ENOENT, unless we have got + * the mft reference of a matching name cached in mref in which case + * return mref. + */ + if (mref) + return mref; + ntfs_log_debug("Entry not found.\n"); + errno = ENOENT; + return -1; +put_err_out: + eo = EIO; + ntfs_log_debug("Corrupt directory. Aborting lookup.\n"); +eo_put_err_out: + ntfs_attr_put_search_ctx(ctx); + errno = eo; + return -1; +close_err_out: + eo = errno; + free(ia); + ntfs_attr_close(ia_na); + goto eo_put_err_out; +} + +/* + * Lookup a file in a directory from its UTF-8 name + * + * The name is first fetched from cache if one is defined + * + * Returns the inode number + * or -1 if not possible (errno tells why) + */ + +u64 ntfs_inode_lookup_by_mbsname(ntfs_inode *dir_ni, const char *name) +{ + int uname_len; + ntfschar *uname = (ntfschar*)NULL; + u64 inum; +#if CACHE_LOOKUP_SIZE + struct CACHED_LOOKUP item; + struct CACHED_LOOKUP *cached; + + /* + * fetch inode from cache + */ + + if (dir_ni->vol->lookup_cache) { + item.name = name; + item.namesize = strlen(name) + 1; + item.parent = dir_ni->mft_no; + cached = (struct CACHED_LOOKUP*)ntfs_fetch_cache( + dir_ni->vol->lookup_cache, GENERIC(&item), + lookup_cache_compare); + if (cached) { + inum = cached->inum; + if (inum == (u64)-1) + errno = ENOENT; + } else { + /* Generate unicode name. */ + uname_len = ntfs_mbstoucs(name, &uname); + if (uname_len >= 0) { + inum = ntfs_inode_lookup_by_name(dir_ni, + uname, uname_len); + item.inum = inum; + /* enter into cache, even if not found */ + ntfs_enter_cache(dir_ni->vol->lookup_cache, + GENERIC(&item), + lookup_cache_compare); + free(uname); + } else + inum = (s64)-1; + } + } else +#endif + { + /* Generate unicode name. */ + uname_len = ntfs_mbstoucs(name, &uname); + if (uname_len >= 0) + inum = ntfs_inode_lookup_by_name(dir_ni, + uname, uname_len); + else + inum = (s64)-1; + } + return (inum); +} + +/* + * Update a cache lookup record when a name has been defined + * + * The UTF-8 name is required + */ + +void ntfs_inode_update_mbsname(ntfs_inode *dir_ni, const char *name, u64 inum) +{ +#if CACHE_LOOKUP_SIZE + struct CACHED_LOOKUP item; + struct CACHED_LOOKUP *cached; + + if (dir_ni->vol->lookup_cache) { + item.name = name; + item.namesize = strlen(name) + 1; + item.parent = dir_ni->mft_no; + item.inum = inum; + cached = (struct CACHED_LOOKUP*)ntfs_enter_cache( + dir_ni->vol->lookup_cache, + GENERIC(&item), lookup_cache_compare); + if (cached) + cached->inum = inum; + } +#endif +} + +/** + * ntfs_pathname_to_inode - Find the inode which represents the given pathname + * @vol: An ntfs volume obtained from ntfs_mount + * @parent: A directory inode to begin the search (may be NULL) + * @pathname: Pathname to be located + * + * Take an ASCII pathname and find the inode that represents it. The function + * splits the path and then descends the directory tree. If @parent is NULL, + * then the root directory '.' will be used as the base for the search. + * + * Return: inode Success, the pathname was valid + * NULL Error, the pathname was invalid, or some other error occurred + */ +ntfs_inode *ntfs_pathname_to_inode(ntfs_volume *vol, ntfs_inode *parent, + const char *pathname) +{ + u64 inum; + int len, err = 0; + char *p, *q; + ntfs_inode *ni; + ntfs_inode *result = NULL; + ntfschar *unicode = NULL; + char *ascii = NULL; +#if CACHE_INODE_SIZE + struct CACHED_INODE item; + struct CACHED_INODE *cached; + char *fullname; +#endif + + if (!vol || !pathname) { + errno = EINVAL; + return NULL; + } + + ntfs_log_trace("path: '%s'\n", pathname); + + ascii = strdup(pathname); + if (!ascii) { + ntfs_log_error("Out of memory.\n"); + err = ENOMEM; + goto out; + } + + p = ascii; + /* Remove leading /'s. */ + while (p && *p && *p == PATH_SEP) + p++; +#if CACHE_INODE_SIZE + fullname = p; + if (p[0] && (p[strlen(p)-1] == PATH_SEP)) + ntfs_log_error("Unnormalized path %s\n",ascii); +#endif + if (parent) { + ni = parent; + } else { +#if CACHE_INODE_SIZE + /* + * fetch inode for full path from cache + */ + if (*fullname) { + item.pathname = fullname; + item.varsize = strlen(fullname) + 1; + cached = (struct CACHED_INODE*)ntfs_fetch_cache( + vol->xinode_cache, GENERIC(&item), + inode_cache_compare); + } else + cached = (struct CACHED_INODE*)NULL; + if (cached) { + /* + * return opened inode if found in cache + */ + inum = MREF(cached->inum); + ni = ntfs_inode_open(vol, inum); + if (!ni) { + ntfs_log_debug("Cannot open inode %llu: %s.\n", + (unsigned long long)inum, p); + err = EIO; + } + result = ni; + goto out; + } +#endif + ni = ntfs_inode_open(vol, FILE_root); + if (!ni) { + ntfs_log_debug("Couldn't open the inode of the root " + "directory.\n"); + err = EIO; + result = (ntfs_inode*)NULL; + goto out; + } + } + + while (p && *p) { + /* Find the end of the first token. */ + q = strchr(p, PATH_SEP); + if (q != NULL) { + *q = '\0'; + } +#if CACHE_INODE_SIZE + /* + * fetch inode for partial path from cache + */ + cached = (struct CACHED_INODE*)NULL; + if (!parent) { + item.pathname = fullname; + item.varsize = strlen(fullname) + 1; + cached = (struct CACHED_INODE*)ntfs_fetch_cache( + vol->xinode_cache, GENERIC(&item), + inode_cache_compare); + if (cached) { + inum = cached->inum; + } + } + /* + * if not in cache, translate, search, then + * insert into cache if found + */ + if (!cached) { + len = ntfs_mbstoucs(p, &unicode); + if (len < 0) { + ntfs_log_perror("Could not convert filename to Unicode:" + " '%s'", p); + err = errno; + goto close; + } else if (len > NTFS_MAX_NAME_LEN) { + err = ENAMETOOLONG; + goto close; + } + inum = ntfs_inode_lookup_by_name(ni, unicode, len); + if (!parent && (inum != (u64) -1)) { + item.inum = inum; + ntfs_enter_cache(vol->xinode_cache, + GENERIC(&item), + inode_cache_compare); + } + } +#else + len = ntfs_mbstoucs(p, &unicode); + if (len < 0) { + ntfs_log_perror("Could not convert filename to Unicode:" + " '%s'", p); + err = errno; + goto close; + } else if (len > NTFS_MAX_NAME_LEN) { + err = ENAMETOOLONG; + goto close; + } + inum = ntfs_inode_lookup_by_name(ni, unicode, len); +#endif + if (inum == (u64) -1) { + ntfs_log_debug("Couldn't find name '%s' in pathname " + "'%s'.\n", p, pathname); + err = ENOENT; + goto close; + } + + if (ni != parent) + if (ntfs_inode_close(ni)) { + err = errno; + goto out; + } + + inum = MREF(inum); + ni = ntfs_inode_open(vol, inum); + if (!ni) { + ntfs_log_debug("Cannot open inode %llu: %s.\n", + (unsigned long long)inum, p); + err = EIO; + goto close; + } + + free(unicode); + unicode = NULL; + + if (q) *q++ = PATH_SEP; /* JPA */ + p = q; + while (p && *p && *p == PATH_SEP) + p++; + } + + result = ni; + ni = NULL; +close: + if (ni && (ni != parent)) + if (ntfs_inode_close(ni) && !err) + err = errno; +out: + free(ascii); + free(unicode); + if (err) + errno = err; + return result; +} + +/* + * The little endian Unicode string ".." for ntfs_readdir(). + */ +static const ntfschar dotdot[3] = { const_cpu_to_le16('.'), + const_cpu_to_le16('.'), + const_cpu_to_le16('\0') }; + +/* + * union index_union - + * More helpers for ntfs_readdir(). + */ +typedef union { + INDEX_ROOT *ir; + INDEX_ALLOCATION *ia; +} index_union __attribute__((__transparent_union__)); + +/** + * enum INDEX_TYPE - + * More helpers for ntfs_readdir(). + */ +typedef enum { + INDEX_TYPE_ROOT, /* index root */ + INDEX_TYPE_ALLOCATION, /* index allocation */ +} INDEX_TYPE; + +/** + * ntfs_filldir - ntfs specific filldir method + * @dir_ni: ntfs inode of current directory + * @pos: current position in directory + * @ivcn_bits: log(2) of index vcn size + * @index_type: specifies whether @iu is an index root or an index allocation + * @iu: index root or index block to which @ie belongs + * @ie: current index entry + * @dirent: context for filldir callback supplied by the caller + * @filldir: filldir callback supplied by the caller + * + * Pass information specifying the current directory entry @ie to the @filldir + * callback. + */ +static int ntfs_filldir(ntfs_inode *dir_ni, s64 *pos, u8 ivcn_bits, + const INDEX_TYPE index_type, index_union iu, INDEX_ENTRY *ie, + void *dirent, ntfs_filldir_t filldir) +{ + FILE_NAME_ATTR *fn = &ie->key.file_name; + unsigned dt_type; + + ntfs_log_trace("Entering.\n"); + + /* Advance the position even if going to skip the entry. */ + if (index_type == INDEX_TYPE_ALLOCATION) + *pos = (u8*)ie - (u8*)iu.ia + (sle64_to_cpu( + iu.ia->index_block_vcn) << ivcn_bits) + + dir_ni->vol->mft_record_size; + else /* if (index_type == INDEX_TYPE_ROOT) */ + *pos = (u8*)ie - (u8*)iu.ir; + /* Skip root directory self reference entry. */ + if (MREF_LE(ie->indexed_file) == FILE_root) + return 0; + if (ie->key.file_name.file_attributes & FILE_ATTR_I30_INDEX_PRESENT) + dt_type = NTFS_DT_DIR; + else if (fn->file_attributes & FILE_ATTR_SYSTEM) + dt_type = NTFS_DT_UNKNOWN; + else + dt_type = NTFS_DT_REG; + return filldir(dirent, fn->file_name, fn->file_name_length, + fn->file_name_type, *pos, + le64_to_cpu(ie->indexed_file), dt_type); +} + +/** + * ntfs_mft_get_parent_ref - find mft reference of parent directory of an inode + * @ni: ntfs inode whose parent directory to find + * + * Find the parent directory of the ntfs inode @ni. To do this, find the first + * file name attribute in the mft record of @ni and return the parent mft + * reference from that. + * + * Note this only makes sense for directories, since files can be hard linked + * from multiple directories and there is no way for us to tell which one is + * being looked for. + * + * Technically directories can have hard links, too, but we consider that as + * illegal as Linux/UNIX do not support directory hard links. + * + * Return the mft reference of the parent directory on success or -1 on error + * with errno set to the error code. + */ +static MFT_REF ntfs_mft_get_parent_ref(ntfs_inode *ni) +{ + MFT_REF mref; + ntfs_attr_search_ctx *ctx; + FILE_NAME_ATTR *fn; + int eo; + + ntfs_log_trace("Entering.\n"); + + if (!ni) { + errno = EINVAL; + return ERR_MREF(-1); + } + + ctx = ntfs_attr_get_search_ctx(ni, NULL); + if (!ctx) + return ERR_MREF(-1); + if (ntfs_attr_lookup(AT_FILE_NAME, AT_UNNAMED, 0, 0, 0, NULL, 0, ctx)) { + ntfs_log_error("No file name found in inode %lld\n", + (unsigned long long)ni->mft_no); + goto err_out; + } + if (ctx->attr->non_resident) { + ntfs_log_error("File name attribute must be resident (inode " + "%lld)\n", (unsigned long long)ni->mft_no); + goto io_err_out; + } + fn = (FILE_NAME_ATTR*)((u8*)ctx->attr + + le16_to_cpu(ctx->attr->value_offset)); + if ((u8*)fn + le32_to_cpu(ctx->attr->value_length) > + (u8*)ctx->attr + le32_to_cpu(ctx->attr->length)) { + ntfs_log_error("Corrupt file name attribute in inode %lld.\n", + (unsigned long long)ni->mft_no); + goto io_err_out; + } + mref = le64_to_cpu(fn->parent_directory); + ntfs_attr_put_search_ctx(ctx); + return mref; +io_err_out: + errno = EIO; +err_out: + eo = errno; + ntfs_attr_put_search_ctx(ctx); + errno = eo; + return ERR_MREF(-1); +} + +/** + * ntfs_readdir - read the contents of an ntfs directory + * @dir_ni: ntfs inode of current directory + * @pos: current position in directory + * @dirent: context for filldir callback supplied by the caller + * @filldir: filldir callback supplied by the caller + * + * Parse the index root and the index blocks that are marked in use in the + * index bitmap and hand each found directory entry to the @filldir callback + * supplied by the caller. + * + * Return 0 on success or -1 on error with errno set to the error code. + * + * Note: Index blocks are parsed in ascending vcn order, from which follows + * that the directory entries are not returned sorted. + */ +int ntfs_readdir(ntfs_inode *dir_ni, s64 *pos, + void *dirent, ntfs_filldir_t filldir) +{ + s64 i_size, br, ia_pos, bmp_pos, ia_start; + ntfs_volume *vol; + ntfs_attr *ia_na, *bmp_na = NULL; + ntfs_attr_search_ctx *ctx = NULL; + u8 *index_end, *bmp = NULL; + INDEX_ROOT *ir; + INDEX_ENTRY *ie; + INDEX_ALLOCATION *ia = NULL; + int rc, ir_pos, bmp_buf_size, bmp_buf_pos, eo; + u32 index_block_size, index_vcn_size; + u8 index_block_size_bits, index_vcn_size_bits; + + ntfs_log_trace("Entering.\n"); + + if (!dir_ni || !pos || !filldir) { + errno = EINVAL; + return -1; + } + + if (!(dir_ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)) { + errno = ENOTDIR; + return -1; + } + + vol = dir_ni->vol; + + ntfs_log_trace("Entering for inode %lld, *pos 0x%llx.\n", + (unsigned long long)dir_ni->mft_no, (long long)*pos); + + /* Open the index allocation attribute. */ + ia_na = ntfs_attr_open(dir_ni, AT_INDEX_ALLOCATION, NTFS_INDEX_I30, 4); + if (!ia_na) { + if (errno != ENOENT) { + ntfs_log_perror("Failed to open index allocation attribute. " + "Directory inode %lld is corrupt or bug", + (unsigned long long)dir_ni->mft_no); + return -1; + } + i_size = 0; + } else + i_size = ia_na->data_size; + + rc = 0; + + /* Are we at end of dir yet? */ + if (*pos >= i_size + vol->mft_record_size) + goto done; + + /* Emulate . and .. for all directories. */ + if (!*pos) { + rc = filldir(dirent, dotdot, 1, FILE_NAME_POSIX, *pos, + MK_MREF(dir_ni->mft_no, + le16_to_cpu(dir_ni->mrec->sequence_number)), + NTFS_DT_DIR); + if (rc) + goto err_out; + ++*pos; + } + if (*pos == 1) { + MFT_REF parent_mref; + + parent_mref = ntfs_mft_get_parent_ref(dir_ni); + if (parent_mref == ERR_MREF(-1)) { + ntfs_log_perror("Parent directory not found"); + goto dir_err_out; + } + + rc = filldir(dirent, dotdot, 2, FILE_NAME_POSIX, *pos, + parent_mref, NTFS_DT_DIR); + if (rc) + goto err_out; + ++*pos; + } + + ctx = ntfs_attr_get_search_ctx(dir_ni, NULL); + if (!ctx) + goto err_out; + + /* Get the offset into the index root attribute. */ + ir_pos = (int)*pos; + /* Find the index root attribute in the mft record. */ + if (ntfs_attr_lookup(AT_INDEX_ROOT, NTFS_INDEX_I30, 4, CASE_SENSITIVE, 0, NULL, + 0, ctx)) { + ntfs_log_perror("Index root attribute missing in directory inode " + "%lld", (unsigned long long)dir_ni->mft_no); + goto dir_err_out; + } + /* Get to the index root value. */ + ir = (INDEX_ROOT*)((u8*)ctx->attr + + le16_to_cpu(ctx->attr->value_offset)); + + /* Determine the size of a vcn in the directory index. */ + index_block_size = le32_to_cpu(ir->index_block_size); + if (index_block_size < NTFS_BLOCK_SIZE || + index_block_size & (index_block_size - 1)) { + ntfs_log_error("Index block size %u is invalid.\n", + (unsigned)index_block_size); + goto dir_err_out; + } + index_block_size_bits = ffs(index_block_size) - 1; + if (vol->cluster_size <= index_block_size) { + index_vcn_size = vol->cluster_size; + index_vcn_size_bits = vol->cluster_size_bits; + } else { + index_vcn_size = vol->sector_size; + index_vcn_size_bits = vol->sector_size_bits; + } + + /* Are we jumping straight into the index allocation attribute? */ + if (*pos >= vol->mft_record_size) { + ntfs_attr_put_search_ctx(ctx); + ctx = NULL; + goto skip_index_root; + } + + index_end = (u8*)&ir->index + le32_to_cpu(ir->index.index_length); + /* The first index entry. */ + ie = (INDEX_ENTRY*)((u8*)&ir->index + + le32_to_cpu(ir->index.entries_offset)); + /* + * Loop until we exceed valid memory (corruption case) or until we + * reach the last entry or until filldir tells us it has had enough + * or signals an error (both covered by the rc test). + */ + for (;; ie = (INDEX_ENTRY*)((u8*)ie + le16_to_cpu(ie->length))) { + ntfs_log_debug("In index root, offset %d.\n", (int)((u8*)ie - (u8*)ir)); + /* Bounds checks. */ + if ((u8*)ie < (u8*)ctx->mrec || (u8*)ie + + sizeof(INDEX_ENTRY_HEADER) > index_end || + (u8*)ie + le16_to_cpu(ie->key_length) > + index_end) + goto dir_err_out; + /* The last entry cannot contain a name. */ + if (ie->ie_flags & INDEX_ENTRY_END) + break; + + if (!le16_to_cpu(ie->length)) + goto dir_err_out; + + /* Skip index root entry if continuing previous readdir. */ + if (ir_pos > (u8*)ie - (u8*)ir) + continue; + /* + * Submit the directory entry to ntfs_filldir(), which will + * invoke the filldir() callback as appropriate. + */ + rc = ntfs_filldir(dir_ni, pos, index_vcn_size_bits, + INDEX_TYPE_ROOT, ir, ie, dirent, filldir); + if (rc) { + ntfs_attr_put_search_ctx(ctx); + ctx = NULL; + goto err_out; + } + } + ntfs_attr_put_search_ctx(ctx); + ctx = NULL; + + /* If there is no index allocation attribute we are finished. */ + if (!ia_na) + goto EOD; + + /* Advance *pos to the beginning of the index allocation. */ + *pos = vol->mft_record_size; + +skip_index_root: + + if (!ia_na) + goto done; + + /* Allocate a buffer for the current index block. */ + ia = ntfs_malloc(index_block_size); + if (!ia) + goto err_out; + + bmp_na = ntfs_attr_open(dir_ni, AT_BITMAP, NTFS_INDEX_I30, 4); + if (!bmp_na) { + ntfs_log_perror("Failed to open index bitmap attribute"); + goto dir_err_out; + } + + /* Get the offset into the index allocation attribute. */ + ia_pos = *pos - vol->mft_record_size; + + bmp_pos = ia_pos >> index_block_size_bits; + if (bmp_pos >> 3 >= bmp_na->data_size) { + ntfs_log_error("Current index position exceeds index bitmap " + "size.\n"); + goto dir_err_out; + } + + bmp_buf_size = min(bmp_na->data_size - (bmp_pos >> 3), 4096); + bmp = ntfs_malloc(bmp_buf_size); + if (!bmp) + goto err_out; + + br = ntfs_attr_pread(bmp_na, bmp_pos >> 3, bmp_buf_size, bmp); + if (br != bmp_buf_size) { + if (br != -1) + errno = EIO; + ntfs_log_perror("Failed to read from index bitmap attribute"); + goto err_out; + } + + bmp_buf_pos = 0; + /* If the index block is not in use find the next one that is. */ + while (!(bmp[bmp_buf_pos >> 3] & (1 << (bmp_buf_pos & 7)))) { +find_next_index_buffer: + bmp_pos++; + bmp_buf_pos++; + /* If we have reached the end of the bitmap, we are done. */ + if (bmp_pos >> 3 >= bmp_na->data_size) + goto EOD; + ia_pos = bmp_pos << index_block_size_bits; + if (bmp_buf_pos >> 3 < bmp_buf_size) + continue; + /* Read next chunk from the index bitmap. */ + bmp_buf_pos = 0; + if ((bmp_pos >> 3) + bmp_buf_size > bmp_na->data_size) + bmp_buf_size = bmp_na->data_size - (bmp_pos >> 3); + br = ntfs_attr_pread(bmp_na, bmp_pos >> 3, bmp_buf_size, bmp); + if (br != bmp_buf_size) { + if (br != -1) + errno = EIO; + ntfs_log_perror("Failed to read from index bitmap attribute"); + goto err_out; + } + } + + ntfs_log_debug("Handling index block 0x%llx.\n", (long long)bmp_pos); + + /* Read the index block starting at bmp_pos. */ + br = ntfs_attr_mst_pread(ia_na, bmp_pos << index_block_size_bits, 1, + index_block_size, ia); + if (br != 1) { + if (br != -1) + errno = EIO; + ntfs_log_perror("Failed to read index block"); + goto err_out; + } + + ia_start = ia_pos & ~(s64)(index_block_size - 1); + if (sle64_to_cpu(ia->index_block_vcn) != ia_start >> + index_vcn_size_bits) { + ntfs_log_error("Actual VCN (0x%llx) of index buffer is different " + "from expected VCN (0x%llx) in inode 0x%llx.\n", + (long long)sle64_to_cpu(ia->index_block_vcn), + (long long)ia_start >> index_vcn_size_bits, + (unsigned long long)dir_ni->mft_no); + goto dir_err_out; + } + if (le32_to_cpu(ia->index.allocated_size) + 0x18 != index_block_size) { + ntfs_log_error("Index buffer (VCN 0x%llx) of directory inode %lld " + "has a size (%u) differing from the directory " + "specified size (%u).\n", (long long)ia_start >> + index_vcn_size_bits, + (unsigned long long)dir_ni->mft_no, + (unsigned) le32_to_cpu(ia->index.allocated_size) + + 0x18, (unsigned)index_block_size); + goto dir_err_out; + } + index_end = (u8*)&ia->index + le32_to_cpu(ia->index.index_length); + if (index_end > (u8*)ia + index_block_size) { + ntfs_log_error("Size of index buffer (VCN 0x%llx) of directory inode " + "%lld exceeds maximum size.\n", + (long long)ia_start >> index_vcn_size_bits, + (unsigned long long)dir_ni->mft_no); + goto dir_err_out; + } + /* The first index entry. */ + ie = (INDEX_ENTRY*)((u8*)&ia->index + + le32_to_cpu(ia->index.entries_offset)); + /* + * Loop until we exceed valid memory (corruption case) or until we + * reach the last entry or until ntfs_filldir tells us it has had + * enough or signals an error (both covered by the rc test). + */ + for (;; ie = (INDEX_ENTRY*)((u8*)ie + le16_to_cpu(ie->length))) { + ntfs_log_debug("In index allocation, offset 0x%llx.\n", + (long long)ia_start + ((u8*)ie - (u8*)ia)); + /* Bounds checks. */ + if ((u8*)ie < (u8*)ia || (u8*)ie + + sizeof(INDEX_ENTRY_HEADER) > index_end || + (u8*)ie + le16_to_cpu(ie->key_length) > + index_end) { + ntfs_log_error("Index entry out of bounds in directory inode " + "%lld.\n", (unsigned long long)dir_ni->mft_no); + goto dir_err_out; + } + /* The last entry cannot contain a name. */ + if (ie->ie_flags & INDEX_ENTRY_END) + break; + + if (!le16_to_cpu(ie->length)) + goto dir_err_out; + + /* Skip index entry if continuing previous readdir. */ + if (ia_pos - ia_start > (u8*)ie - (u8*)ia) + continue; + /* + * Submit the directory entry to ntfs_filldir(), which will + * invoke the filldir() callback as appropriate. + */ + rc = ntfs_filldir(dir_ni, pos, index_vcn_size_bits, + INDEX_TYPE_ALLOCATION, ia, ie, dirent, filldir); + if (rc) + goto err_out; + } + goto find_next_index_buffer; +EOD: + /* We are finished, set *pos to EOD. */ + *pos = i_size + vol->mft_record_size; +done: + free(ia); + free(bmp); + if (bmp_na) + ntfs_attr_close(bmp_na); + if (ia_na) + ntfs_attr_close(ia_na); + ntfs_log_debug("EOD, *pos 0x%llx, returning 0.\n", (long long)*pos); + return 0; +dir_err_out: + errno = EIO; +err_out: + eo = errno; + ntfs_log_trace("failed.\n"); + if (ctx) + ntfs_attr_put_search_ctx(ctx); + free(ia); + free(bmp); + if (bmp_na) + ntfs_attr_close(bmp_na); + if (ia_na) + ntfs_attr_close(ia_na); + errno = eo; + return -1; +} + + +/** + * __ntfs_create - create object on ntfs volume + * @dir_ni: ntfs inode for directory in which create new object + * @securid: id of inheritable security descriptor, 0 if none + * @name: unicode name of new object + * @name_len: length of the name in unicode characters + * @type: type of the object to create + * @dev: major and minor device numbers (obtained from makedev()) + * @target: target in unicode (only for symlinks) + * @target_len: length of target in unicode characters + * + * Internal, use ntfs_create{,_device,_symlink} wrappers instead. + * + * @type can be: + * S_IFREG to create regular file + * S_IFDIR to create directory + * S_IFBLK to create block device + * S_IFCHR to create character device + * S_IFLNK to create symbolic link + * S_IFIFO to create FIFO + * S_IFSOCK to create socket + * other values are invalid. + * + * @dev is used only if @type is S_IFBLK or S_IFCHR, in other cases its value + * ignored. + * + * @target and @target_len are used only if @type is S_IFLNK, in other cases + * their value ignored. + * + * Return opened ntfs inode that describes created object on success or NULL + * on error with errno set to the error code. + */ +static ntfs_inode *__ntfs_create(ntfs_inode *dir_ni, le32 securid, + ntfschar *name, u8 name_len, mode_t type, dev_t dev, + ntfschar *target, int target_len) +{ + ntfs_inode *ni; + int rollback_data = 0, rollback_sd = 0; + FILE_NAME_ATTR *fn = NULL; + STANDARD_INFORMATION *si = NULL; + int err, fn_len, si_len; + + ntfs_log_trace("Entering.\n"); + + /* Sanity checks. */ + if (!dir_ni || !name || !name_len) { + ntfs_log_error("Invalid arguments.\n"); + errno = EINVAL; + return NULL; + } + + if (dir_ni->flags & FILE_ATTR_REPARSE_POINT) { + errno = EOPNOTSUPP; + return NULL; + } + + ni = ntfs_mft_record_alloc(dir_ni->vol, NULL); + if (!ni) + return NULL; +#if CACHE_NIDATA_SIZE + ntfs_inode_invalidate(dir_ni->vol, ni->mft_no); +#endif + /* + * Create STANDARD_INFORMATION attribute. + * JPA Depending on available inherited security descriptor, + * Write STANDARD_INFORMATION v1.2 (no inheritance) or v3 + */ + if (securid) + si_len = sizeof(STANDARD_INFORMATION); + else + si_len = offsetof(STANDARD_INFORMATION, v1_end); + si = ntfs_calloc(si_len); + if (!si) { + err = errno; + goto err_out; + } + si->creation_time = ni->creation_time; + si->last_data_change_time = ni->last_data_change_time; + si->last_mft_change_time = ni->last_mft_change_time; + si->last_access_time = ni->last_access_time; + if (securid) { + set_nino_flag(ni, v3_Extensions); + ni->owner_id = si->owner_id = 0; + ni->security_id = si->security_id = securid; + ni->quota_charged = si->quota_charged = const_cpu_to_le64(0); + ni->usn = si->usn = const_cpu_to_le64(0); + } else + clear_nino_flag(ni, v3_Extensions); + if (!S_ISREG(type) && !S_ISDIR(type)) { + si->file_attributes = FILE_ATTR_SYSTEM; + ni->flags = FILE_ATTR_SYSTEM; + } + ni->flags |= FILE_ATTR_ARCHIVE; + if ((dir_ni->flags & FILE_ATTR_COMPRESSED) + && (S_ISREG(type) || S_ISDIR(type))) + ni->flags |= FILE_ATTR_COMPRESSED; + /* Add STANDARD_INFORMATION to inode. */ + if (ntfs_attr_add(ni, AT_STANDARD_INFORMATION, AT_UNNAMED, 0, + (u8*)si, si_len)) { + err = errno; + ntfs_log_error("Failed to add STANDARD_INFORMATION " + "attribute.\n"); + goto err_out; + } + + if (!securid) { + if (ntfs_sd_add_everyone(ni)) { + err = errno; + goto err_out; + } + } + rollback_sd = 1; + + if (S_ISDIR(type)) { + INDEX_ROOT *ir = NULL; + INDEX_ENTRY *ie; + int ir_len, index_len; + + /* Create INDEX_ROOT attribute. */ + index_len = sizeof(INDEX_HEADER) + sizeof(INDEX_ENTRY_HEADER); + ir_len = offsetof(INDEX_ROOT, index) + index_len; + ir = ntfs_calloc(ir_len); + if (!ir) { + err = errno; + goto err_out; + } + ir->type = AT_FILE_NAME; + ir->collation_rule = COLLATION_FILE_NAME; + ir->index_block_size = cpu_to_le32(ni->vol->indx_record_size); + if (ni->vol->cluster_size <= ni->vol->indx_record_size) + ir->clusters_per_index_block = + ni->vol->indx_record_size >> + ni->vol->cluster_size_bits; + else + ir->clusters_per_index_block = + ni->vol->indx_record_size >> + ni->vol->sector_size_bits; + ir->index.entries_offset = cpu_to_le32(sizeof(INDEX_HEADER)); + ir->index.index_length = cpu_to_le32(index_len); + ir->index.allocated_size = cpu_to_le32(index_len); + ie = (INDEX_ENTRY*)((u8*)ir + sizeof(INDEX_ROOT)); + ie->length = cpu_to_le16(sizeof(INDEX_ENTRY_HEADER)); + ie->key_length = 0; + ie->ie_flags = INDEX_ENTRY_END; + /* Add INDEX_ROOT attribute to inode. */ + if (ntfs_attr_add(ni, AT_INDEX_ROOT, NTFS_INDEX_I30, 4, + (u8*)ir, ir_len)) { + err = errno; + free(ir); + ntfs_log_error("Failed to add INDEX_ROOT attribute.\n"); + goto err_out; + } + free(ir); + } else { + INTX_FILE *data; + int data_len; + + switch (type) { + case S_IFBLK: + case S_IFCHR: + data_len = offsetof(INTX_FILE, device_end); + data = ntfs_malloc(data_len); + if (!data) { + err = errno; + goto err_out; + } + data->major = cpu_to_le64(major(dev)); + data->minor = cpu_to_le64(minor(dev)); + if (type == S_IFBLK) + data->magic = INTX_BLOCK_DEVICE; + if (type == S_IFCHR) + data->magic = INTX_CHARACTER_DEVICE; + break; + case S_IFLNK: + data_len = sizeof(INTX_FILE_TYPES) + + target_len * sizeof(ntfschar); + data = ntfs_malloc(data_len); + if (!data) { + err = errno; + goto err_out; + } + data->magic = INTX_SYMBOLIC_LINK; + memcpy(data->target, target, + target_len * sizeof(ntfschar)); + break; + case S_IFSOCK: + data = NULL; + data_len = 1; + break; + default: /* FIFO or regular file. */ + data = NULL; + data_len = 0; + break; + } + /* Add DATA attribute to inode. */ + if (ntfs_attr_add(ni, AT_DATA, AT_UNNAMED, 0, (u8*)data, + data_len)) { + err = errno; + ntfs_log_error("Failed to add DATA attribute.\n"); + free(data); + goto err_out; + } + rollback_data = 1; + free(data); + } + /* Create FILE_NAME attribute. */ + fn_len = sizeof(FILE_NAME_ATTR) + name_len * sizeof(ntfschar); + fn = ntfs_calloc(fn_len); + if (!fn) { + err = errno; + goto err_out; + } + fn->parent_directory = MK_LE_MREF(dir_ni->mft_no, + le16_to_cpu(dir_ni->mrec->sequence_number)); + fn->file_name_length = name_len; + fn->file_name_type = FILE_NAME_POSIX; + if (S_ISDIR(type)) + fn->file_attributes = FILE_ATTR_I30_INDEX_PRESENT; + if (!S_ISREG(type) && !S_ISDIR(type)) + fn->file_attributes = FILE_ATTR_SYSTEM; + else + fn->file_attributes |= ni->flags & FILE_ATTR_COMPRESSED; + fn->file_attributes |= FILE_ATTR_ARCHIVE; + fn->creation_time = ni->creation_time; + fn->last_data_change_time = ni->last_data_change_time; + fn->last_mft_change_time = ni->last_mft_change_time; + fn->last_access_time = ni->last_access_time; + if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) + fn->data_size = fn->allocated_size = const_cpu_to_le64(0); + else { + fn->data_size = cpu_to_sle64(ni->data_size); + fn->allocated_size = cpu_to_sle64(ni->allocated_size); + } + memcpy(fn->file_name, name, name_len * sizeof(ntfschar)); + /* Add FILE_NAME attribute to inode. */ + if (ntfs_attr_add(ni, AT_FILE_NAME, AT_UNNAMED, 0, (u8*)fn, fn_len)) { + err = errno; + ntfs_log_error("Failed to add FILE_NAME attribute.\n"); + goto err_out; + } + /* Add FILE_NAME attribute to index. */ + if (ntfs_index_add_filename(dir_ni, fn, MK_MREF(ni->mft_no, + le16_to_cpu(ni->mrec->sequence_number)))) { + err = errno; + ntfs_log_perror("Failed to add entry to the index"); + goto err_out; + } + /* Set hard links count and directory flag. */ + ni->mrec->link_count = cpu_to_le16(1); + if (S_ISDIR(type)) + ni->mrec->flags |= MFT_RECORD_IS_DIRECTORY; + ntfs_inode_mark_dirty(ni); + /* Done! */ + free(fn); + free(si); + ntfs_log_trace("Done.\n"); + return ni; +err_out: + ntfs_log_trace("Failed.\n"); + + if (rollback_sd) + ntfs_attr_remove(ni, AT_SECURITY_DESCRIPTOR, AT_UNNAMED, 0); + + if (rollback_data) + ntfs_attr_remove(ni, AT_DATA, AT_UNNAMED, 0); + /* + * Free extent MFT records (should not exist any with current + * ntfs_create implementation, but for any case if something will be + * changed in the future). + */ + while (ni->nr_extents) + if (ntfs_mft_record_free(ni->vol, *(ni->extent_nis))) { + err = errno; + ntfs_log_error("Failed to free extent MFT record. " + "Leaving inconsistent metadata.\n"); + } + if (ntfs_mft_record_free(ni->vol, ni)) + ntfs_log_error("Failed to free MFT record. " + "Leaving inconsistent metadata. Run chkdsk.\n"); + free(fn); + free(si); + errno = err; + return NULL; +} + +/** + * Some wrappers around __ntfs_create() ... + */ + +ntfs_inode *ntfs_create(ntfs_inode *dir_ni, le32 securid, ntfschar *name, + u8 name_len, mode_t type) +{ + if (type != S_IFREG && type != S_IFDIR && type != S_IFIFO && + type != S_IFSOCK) { + ntfs_log_error("Invalid arguments.\n"); + return NULL; + } + return __ntfs_create(dir_ni, securid, name, name_len, type, 0, NULL, 0); +} + +ntfs_inode *ntfs_create_device(ntfs_inode *dir_ni, le32 securid, + ntfschar *name, u8 name_len, mode_t type, dev_t dev) +{ + if (type != S_IFCHR && type != S_IFBLK) { + ntfs_log_error("Invalid arguments.\n"); + return NULL; + } + return __ntfs_create(dir_ni, securid, name, name_len, type, dev, NULL, 0); +} + +ntfs_inode *ntfs_create_symlink(ntfs_inode *dir_ni, le32 securid, + ntfschar *name, u8 name_len, ntfschar *target, int target_len) +{ + if (!target || !target_len) { + ntfs_log_error("%s: Invalid argument (%p, %d)\n", __FUNCTION__, + target, target_len); + return NULL; + } + return __ntfs_create(dir_ni, securid, name, name_len, S_IFLNK, 0, + target, target_len); +} + +int ntfs_check_empty_dir(ntfs_inode *ni) +{ + ntfs_attr *na; + int ret = 0; + + if (!(ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)) + return 0; + + na = ntfs_attr_open(ni, AT_INDEX_ROOT, NTFS_INDEX_I30, 4); + if (!na) { + errno = EIO; + ntfs_log_perror("Failed to open directory"); + return -1; + } + + /* Non-empty directory? */ + if ((na->data_size != sizeof(INDEX_ROOT) + sizeof(INDEX_ENTRY_HEADER))){ + /* Both ENOTEMPTY and EEXIST are ok. We use the more common. */ + errno = ENOTEMPTY; + ntfs_log_debug("Directory is not empty\n"); + ret = -1; + } + + ntfs_attr_close(na); + return ret; +} + +static int ntfs_check_unlinkable_dir(ntfs_inode *ni, FILE_NAME_ATTR *fn) +{ + int link_count = le16_to_cpu(ni->mrec->link_count); + int ret; + + ret = ntfs_check_empty_dir(ni); + if (!ret || errno != ENOTEMPTY) + return ret; + /* + * Directory is non-empty, so we can unlink only if there is more than + * one "real" hard link, i.e. links aren't different DOS and WIN32 names + */ + if ((link_count == 1) || + (link_count == 2 && fn->file_name_type == FILE_NAME_DOS)) { + errno = ENOTEMPTY; + ntfs_log_debug("Non-empty directory without hard links\n"); + goto no_hardlink; + } + + ret = 0; +no_hardlink: + return ret; +} + +/** + * ntfs_delete - delete file or directory from ntfs volume + * @ni: ntfs inode for object to delte + * @dir_ni: ntfs inode for directory in which delete object + * @name: unicode name of the object to delete + * @name_len: length of the name in unicode characters + * + * @ni is always closed after the call to this function (even if it failed), + * user does not need to call ntfs_inode_close himself. + * + * Return 0 on success or -1 on error with errno set to the error code. + */ +int ntfs_delete(ntfs_volume *vol, const char *pathname, + ntfs_inode *ni, ntfs_inode *dir_ni, ntfschar *name, u8 name_len) +{ + ntfs_attr_search_ctx *actx = NULL; + FILE_NAME_ATTR *fn = NULL; + BOOL looking_for_dos_name = FALSE, looking_for_win32_name = FALSE; + BOOL case_sensitive_match = TRUE; + int err = 0; +#if CACHE_NIDATA_SIZE + int i; +#endif +#if CACHE_INODE_SIZE + struct CACHED_INODE item; + const char *p; + u64 inum = (u64)-1; + int count; +#endif +#if CACHE_LOOKUP_SIZE + struct CACHED_LOOKUP lkitem; +#endif + + ntfs_log_trace("Entering.\n"); + + if (!ni || !dir_ni || !name || !name_len) { + ntfs_log_error("Invalid arguments.\n"); + errno = EINVAL; + goto err_out; + } + if (ni->nr_extents == -1) + ni = ni->base_ni; + if (dir_ni->nr_extents == -1) + dir_ni = dir_ni->base_ni; + /* + * Search for FILE_NAME attribute with such name. If it's in POSIX or + * WIN32_AND_DOS namespace, then simply remove it from index and inode. + * If filename in DOS or in WIN32 namespace, then remove DOS name first, + * only then remove WIN32 name. + */ + actx = ntfs_attr_get_search_ctx(ni, NULL); + if (!actx) + goto err_out; +search: + while (!ntfs_attr_lookup(AT_FILE_NAME, AT_UNNAMED, 0, CASE_SENSITIVE, + 0, NULL, 0, actx)) { + char *s; + BOOL case_sensitive = IGNORE_CASE; + + errno = 0; + fn = (FILE_NAME_ATTR*)((u8*)actx->attr + + le16_to_cpu(actx->attr->value_offset)); + s = ntfs_attr_name_get(fn->file_name, fn->file_name_length); + ntfs_log_trace("name: '%s' type: %d dos: %d win32: %d " + "case: %d\n", s, fn->file_name_type, + looking_for_dos_name, looking_for_win32_name, + case_sensitive_match); + ntfs_attr_name_free(&s); + if (looking_for_dos_name) { + if (fn->file_name_type == FILE_NAME_DOS) + break; + else + continue; + } + if (looking_for_win32_name) { + if (fn->file_name_type == FILE_NAME_WIN32) + break; + else + continue; + } + + /* Ignore hard links from other directories */ + if (dir_ni->mft_no != MREF_LE(fn->parent_directory)) { + ntfs_log_debug("MFT record numbers don't match " + "(%llu != %llu)\n", + (long long unsigned)dir_ni->mft_no, + (long long unsigned)MREF_LE(fn->parent_directory)); + continue; + } + + if (fn->file_name_type == FILE_NAME_POSIX || case_sensitive_match) + case_sensitive = CASE_SENSITIVE; + + if (ntfs_names_are_equal(fn->file_name, fn->file_name_length, + name, name_len, case_sensitive, + ni->vol->upcase, ni->vol->upcase_len)){ + + if (fn->file_name_type == FILE_NAME_WIN32) { + looking_for_dos_name = TRUE; + ntfs_attr_reinit_search_ctx(actx); + continue; + } + if (fn->file_name_type == FILE_NAME_DOS) + looking_for_dos_name = TRUE; + break; + } + } + if (errno) { + /* + * If case sensitive search failed, then try once again + * ignoring case. + */ + if (errno == ENOENT && case_sensitive_match) { + case_sensitive_match = FALSE; + ntfs_attr_reinit_search_ctx(actx); + goto search; + } + goto err_out; + } + + if (ntfs_check_unlinkable_dir(ni, fn) < 0) + goto err_out; + + if (ntfs_index_remove(dir_ni, ni, fn, le32_to_cpu(actx->attr->value_length))) + goto err_out; + + if (ntfs_attr_record_rm(actx)) + goto err_out; + + ni->mrec->link_count = cpu_to_le16(le16_to_cpu( + ni->mrec->link_count) - 1); + + ntfs_inode_mark_dirty(ni); + if (looking_for_dos_name) { + looking_for_dos_name = FALSE; + looking_for_win32_name = TRUE; + ntfs_attr_reinit_search_ctx(actx); + goto search; + } + /* TODO: Update object id, quota and securiry indexes if required. */ + /* + * If hard link count is not equal to zero then we are done. In other + * case there are no reference to this inode left, so we should free all + * non-resident attributes and mark all MFT record as not in use. + */ +#if CACHE_LOOKUP_SIZE + /* invalidate entry in lookup cache */ + lkitem.name = (const char*)NULL; + lkitem.namesize = 0; + lkitem.inum = ni->mft_no; + lkitem.parent = dir_ni->mft_no; + ntfs_invalidate_cache(vol->lookup_cache, GENERIC(&lkitem), + lookup_cache_inv_compare, CACHE_NOHASH); +#endif +#if CACHE_INODE_SIZE + inum = ni->mft_no; + if (pathname) { + /* invalide cache entry, even if there was an error */ + /* Remove leading /'s. */ + p = pathname; + while (*p == PATH_SEP) + p++; + if (p[0] && (p[strlen(p)-1] == PATH_SEP)) + ntfs_log_error("Unnormalized path %s\n",pathname); + item.pathname = p; + item.varsize = strlen(p); + } else { + item.pathname = (const char*)NULL; + item.varsize = 0; + } + item.inum = inum; + count = ntfs_invalidate_cache(vol->xinode_cache, GENERIC(&item), + inode_cache_inv_compare, CACHE_NOHASH); + if (pathname && !count) + ntfs_log_error("Could not delete inode cache entry for %s\n", + pathname); +#endif + if (ni->mrec->link_count) { + ntfs_inode_update_times(ni, NTFS_UPDATE_CTIME); + goto ok; + } + if (ntfs_delete_reparse_index(ni)) { + /* + * Failed to remove the reparse index : proceed anyway + * This is not a critical error, the entry is useless + * because of sequence_number, and stopping file deletion + * would be much worse as the file is not referenced now. + */ + err = errno; + } + if (ntfs_delete_object_id_index(ni)) { + /* + * Failed to remove the object id index : proceed anyway + * This is not a critical error. + */ + err = errno; + } + ntfs_attr_reinit_search_ctx(actx); + while (!ntfs_attrs_walk(actx)) { + if (actx->attr->non_resident) { + runlist *rl; + + rl = ntfs_mapping_pairs_decompress(ni->vol, actx->attr, + NULL); + if (!rl) { + err = errno; + ntfs_log_error("Failed to decompress runlist. " + "Leaving inconsistent metadata.\n"); + continue; + } + if (ntfs_cluster_free_from_rl(ni->vol, rl)) { + err = errno; + ntfs_log_error("Failed to free clusters. " + "Leaving inconsistent metadata.\n"); + continue; + } + free(rl); + } + } + if (errno != ENOENT) { + err = errno; + ntfs_log_error("Attribute enumeration failed. " + "Probably leaving inconsistent metadata.\n"); + } + /* All extents should be attached after attribute walk. */ +#if CACHE_NIDATA_SIZE + /* + * Disconnect extents before deleting them, so they are + * not wrongly moved to cache through the chainings + */ + for (i=ni->nr_extents-1; i>=0; i--) { + ni->extent_nis[i]->base_ni = (ntfs_inode*)NULL; + ni->extent_nis[i]->nr_extents = 0; + if (ntfs_mft_record_free(ni->vol, ni->extent_nis[i])) { + err = errno; + ntfs_log_error("Failed to free extent MFT record. " + "Leaving inconsistent metadata.\n"); + } + } + free(ni->extent_nis); + ni->nr_extents = 0; + ni->extent_nis = (ntfs_inode**)NULL; +#else + while (ni->nr_extents) + if (ntfs_mft_record_free(ni->vol, *(ni->extent_nis))) { + err = errno; + ntfs_log_error("Failed to free extent MFT record. " + "Leaving inconsistent metadata.\n"); + } +#endif + if (ntfs_mft_record_free(ni->vol, ni)) { + err = errno; + ntfs_log_error("Failed to free base MFT record. " + "Leaving inconsistent metadata.\n"); + } + ni = NULL; +ok: + ntfs_inode_update_times(dir_ni, NTFS_UPDATE_MCTIME); +out: + if (actx) + ntfs_attr_put_search_ctx(actx); + if (ntfs_inode_close(dir_ni) && !err) + err = errno; + if (ntfs_inode_close(ni) && !err) + err = errno; + if (err) { + errno = err; + ntfs_log_debug("Could not delete file: %s\n", strerror(errno)); + return -1; + } + ntfs_log_trace("Done.\n"); + return 0; +err_out: + err = errno; + goto out; +} + +/** + * ntfs_link - create hard link for file or directory + * @ni: ntfs inode for object to create hard link + * @dir_ni: ntfs inode for directory in which new link should be placed + * @name: unicode name of the new link + * @name_len: length of the name in unicode characters + * + * NOTE: At present we allow creating hardlinks to directories, we use them + * in a temporary state during rename. But it's defenitely bad idea to have + * hard links to directories as a result of operation. + * FIXME: Create internal __ntfs_link that allows hard links to a directories + * and external ntfs_link that do not. Write ntfs_rename that uses __ntfs_link. + * + * Return 0 on success or -1 on error with errno set to the error code. + */ +static int ntfs_link_i(ntfs_inode *ni, ntfs_inode *dir_ni, ntfschar *name, + u8 name_len, FILE_NAME_TYPE_FLAGS nametype) +{ + FILE_NAME_ATTR *fn = NULL; + int fn_len, err; + + ntfs_log_trace("Entering.\n"); + + if (!ni || !dir_ni || !name || !name_len || + ni->mft_no == dir_ni->mft_no) { + err = EINVAL; + ntfs_log_perror("ntfs_link wrong arguments"); + goto err_out; + } + + if ((ni->flags & FILE_ATTR_REPARSE_POINT) + && !ntfs_possible_symlink(ni)) { + err = EOPNOTSUPP; + goto err_out; + } + + /* Create FILE_NAME attribute. */ + fn_len = sizeof(FILE_NAME_ATTR) + name_len * sizeof(ntfschar); + fn = ntfs_calloc(fn_len); + if (!fn) { + err = errno; + goto err_out; + } + fn->parent_directory = MK_LE_MREF(dir_ni->mft_no, + le16_to_cpu(dir_ni->mrec->sequence_number)); + fn->file_name_length = name_len; + fn->file_name_type = nametype; + fn->file_attributes = ni->flags; + if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) { + fn->file_attributes |= FILE_ATTR_I30_INDEX_PRESENT; + fn->data_size = fn->allocated_size = const_cpu_to_le64(0); + } else { + fn->allocated_size = cpu_to_sle64(ni->allocated_size); + fn->data_size = cpu_to_sle64(ni->data_size); + } + fn->creation_time = ni->creation_time; + fn->last_data_change_time = ni->last_data_change_time; + fn->last_mft_change_time = ni->last_mft_change_time; + fn->last_access_time = ni->last_access_time; + memcpy(fn->file_name, name, name_len * sizeof(ntfschar)); + /* Add FILE_NAME attribute to index. */ + if (ntfs_index_add_filename(dir_ni, fn, MK_MREF(ni->mft_no, + le16_to_cpu(ni->mrec->sequence_number)))) { + err = errno; + ntfs_log_perror("Failed to add filename to the index"); + goto err_out; + } + /* Add FILE_NAME attribute to inode. */ + if (ntfs_attr_add(ni, AT_FILE_NAME, AT_UNNAMED, 0, (u8*)fn, fn_len)) { + ntfs_log_error("Failed to add FILE_NAME attribute.\n"); + err = errno; + /* Try to remove just added attribute from index. */ + if (ntfs_index_remove(dir_ni, ni, fn, fn_len)) + goto rollback_failed; + goto err_out; + } + /* Increment hard links count. */ + ni->mrec->link_count = cpu_to_le16(le16_to_cpu( + ni->mrec->link_count) + 1); + /* Done! */ + ntfs_inode_mark_dirty(ni); + free(fn); + ntfs_log_trace("Done.\n"); + return 0; +rollback_failed: + ntfs_log_error("Rollback failed. Leaving inconsistent metadata.\n"); +err_out: + free(fn); + errno = err; + return -1; +} + +int ntfs_link(ntfs_inode *ni, ntfs_inode *dir_ni, ntfschar *name, u8 name_len) +{ + return (ntfs_link_i(ni, dir_ni, name, name_len, FILE_NAME_POSIX)); +} + +/* + * Get a parent directory from an inode entry + * + * This is only used in situations where the path used to access + * the current file is not known for sure. The result may be different + * from the path when the file is linked in several parent directories. + * + * Currently this is only used for translating ".." in the target + * of a Vista relative symbolic link + */ + +ntfs_inode *ntfs_dir_parent_inode(ntfs_inode *ni) +{ + ntfs_inode *dir_ni = (ntfs_inode*)NULL; + u64 inum; + FILE_NAME_ATTR *fn; + ntfs_attr_search_ctx *ctx; + + if (ni->mft_no != FILE_root) { + /* find the name in the attributes */ + ctx = ntfs_attr_get_search_ctx(ni, NULL); + if (!ctx) + return ((ntfs_inode*)NULL); + + if (!ntfs_attr_lookup(AT_FILE_NAME, AT_UNNAMED, 0, + CASE_SENSITIVE, 0, NULL, 0, ctx)) { + /* We know this will always be resident. */ + fn = (FILE_NAME_ATTR*)((u8*)ctx->attr + + le16_to_cpu(ctx->attr->value_offset)); + inum = le64_to_cpu(fn->parent_directory); + if (inum != (u64)-1) { + dir_ni = ntfs_inode_open(ni->vol, MREF(inum)); + } + } + ntfs_attr_put_search_ctx(ctx); + } + return (dir_ni); +} + +#ifdef HAVE_SETXATTR + +#define MAX_DOS_NAME_LENGTH 12 + +/* + * Get a DOS name for a file in designated directory + * + * Returns size if found + * 0 if not found + * -1 if there was an error (described by errno) + */ + +static int get_dos_name(ntfs_inode *ni, u64 dnum, ntfschar *dosname) +{ + size_t outsize = 0; + FILE_NAME_ATTR *fn; + ntfs_attr_search_ctx *ctx; + + /* find the name in the attributes */ + ctx = ntfs_attr_get_search_ctx(ni, NULL); + if (!ctx) + return -1; + + while (!ntfs_attr_lookup(AT_FILE_NAME, AT_UNNAMED, 0, CASE_SENSITIVE, + 0, NULL, 0, ctx)) { + /* We know this will always be resident. */ + fn = (FILE_NAME_ATTR*)((u8*)ctx->attr + + le16_to_cpu(ctx->attr->value_offset)); + + if ((fn->file_name_type & FILE_NAME_DOS) + && (MREF_LE(fn->parent_directory) == dnum)) { + /* + * Found a DOS or WIN32+DOS name for the entry + * copy name, after truncation for safety + */ + outsize = fn->file_name_length; +/* TODO : reject if name is too long ? */ + if (outsize > MAX_DOS_NAME_LENGTH) + outsize = MAX_DOS_NAME_LENGTH; + memcpy(dosname,fn->file_name,outsize*sizeof(ntfschar)); + } + } + ntfs_attr_put_search_ctx(ctx); + return (outsize); +} + + +/* + * Get a long name for a file in designated directory + * + * Returns size if found + * 0 if not found + * -1 if there was an error (described by errno) + */ + +static int get_long_name(ntfs_inode *ni, u64 dnum, ntfschar *longname) +{ + size_t outsize = 0; + FILE_NAME_ATTR *fn; + ntfs_attr_search_ctx *ctx; + + /* find the name in the attributes */ + ctx = ntfs_attr_get_search_ctx(ni, NULL); + if (!ctx) + return -1; + + /* first search for WIN32 or DOS+WIN32 names */ + while (!ntfs_attr_lookup(AT_FILE_NAME, AT_UNNAMED, 0, CASE_SENSITIVE, + 0, NULL, 0, ctx)) { + /* We know this will always be resident. */ + fn = (FILE_NAME_ATTR*)((u8*)ctx->attr + + le16_to_cpu(ctx->attr->value_offset)); + + if ((fn->file_name_type & FILE_NAME_WIN32) + && (MREF_LE(fn->parent_directory) == dnum)) { + /* + * Found a WIN32 or WIN32+DOS name for the entry + * copy name + */ + outsize = fn->file_name_length; + memcpy(longname,fn->file_name,outsize*sizeof(ntfschar)); + } + } + /* if not found search for POSIX names */ + if (!outsize) { + ntfs_attr_reinit_search_ctx(ctx); + while (!ntfs_attr_lookup(AT_FILE_NAME, AT_UNNAMED, 0, CASE_SENSITIVE, + 0, NULL, 0, ctx)) { + /* We know this will always be resident. */ + fn = (FILE_NAME_ATTR*)((u8*)ctx->attr + + le16_to_cpu(ctx->attr->value_offset)); + + if ((fn->file_name_type == FILE_NAME_POSIX) + && (MREF_LE(fn->parent_directory) == dnum)) { + /* + * Found a POSIX name for the entry + * copy name + */ + outsize = fn->file_name_length; + memcpy(longname,fn->file_name,outsize*sizeof(ntfschar)); + } + } + } + ntfs_attr_put_search_ctx(ctx); + return (outsize); +} + + +/* + * Get the ntfs DOS name into an extended attribute + */ + +int ntfs_get_ntfs_dos_name(ntfs_inode *ni, ntfs_inode *dir_ni, + char *value, size_t size) +{ + int outsize = 0; + char *outname = (char*)NULL; + u64 dnum; + int doslen; + ntfschar dosname[MAX_DOS_NAME_LENGTH]; + + dnum = dir_ni->mft_no; + doslen = get_dos_name(ni, dnum, dosname); + if (doslen > 0) { + /* + * Found a DOS name for the entry, make + * uppercase and encode into the buffer + * if there is enough space + */ + ntfs_name_upcase(dosname, doslen, + ni->vol->upcase, ni->vol->upcase_len); + if (ntfs_ucstombs(dosname, doslen, &outname, size) < 0) { + ntfs_log_error("Cannot represent dosname in current locale.\n"); + outsize = -errno; + } else { + outsize = strlen(outname); + if (value && (outsize <= (int)size)) + memcpy(value, outname, outsize); + else + if (size && (outsize > (int)size)) + outsize = -ERANGE; + free(outname); + } + } else { + if (doslen == 0) + errno = ENODATA; + outsize = -errno; + } + return (outsize); +} + +/* + * Change the name space of an existing file or directory + * + * Returns the old namespace if successful + * -1 if an error occurred (described by errno) + */ + +static int set_namespace(ntfs_inode *ni, ntfs_inode *dir_ni, + ntfschar *name, int len, + FILE_NAME_TYPE_FLAGS nametype) +{ + ntfs_attr_search_ctx *actx; + ntfs_index_context *icx; + FILE_NAME_ATTR *fnx; + FILE_NAME_ATTR *fn = NULL; + BOOL found; + int lkup; + int ret; + + ret = -1; + actx = ntfs_attr_get_search_ctx(ni, NULL); + if (actx) { + found = FALSE; + do { + lkup = ntfs_attr_lookup(AT_FILE_NAME, AT_UNNAMED, 0, + CASE_SENSITIVE, 0, NULL, 0, actx); + if (!lkup) { + fn = (FILE_NAME_ATTR*)((u8*)actx->attr + + le16_to_cpu(actx->attr->value_offset)); + found = (MREF_LE(fn->parent_directory) + == dir_ni->mft_no) + && !memcmp(fn->file_name, name, + len*sizeof(ntfschar)); + } + } while (!lkup && !found); + if (found) { + icx = ntfs_index_ctx_get(dir_ni, NTFS_INDEX_I30, 4); + if (icx) { + lkup = ntfs_index_lookup((char*)fn, len, icx); + if (!lkup && icx->data && icx->data_len) { + fnx = (FILE_NAME_ATTR*)icx->data; + ret = fn->file_name_type; + fn->file_name_type = nametype; + fnx->file_name_type = nametype; + ntfs_inode_mark_dirty(ni); + ntfs_index_entry_mark_dirty(icx); + } + ntfs_index_ctx_put(icx); + } + } + ntfs_attr_put_search_ctx(actx); + } + return (ret); +} + +/* + * Set a DOS name to a file and adjust name spaces + * + * If the new names are collapsible (same uppercased chars) : + * + * - the existing DOS name or DOS+Win32 name is made Posix + * - if it was a real DOS name, the existing long name is made DOS+Win32 + * and the existing DOS name is deleted + * - finally the existing long name is made DOS+Win32 unless already done + * + * If the new names are not collapsible : + * + * - insert the short name as a DOS name + * - delete the old long name or existing short name + * - insert the new long name (as a Win32 or DOS+Win32 name) + * + * Deleting the old long name will not delete the file + * provided the old name was in the Posix name space, + * because the alternate name has been set before. + * + * The inodes of file and parent directory are always closed + * + * Returns 0 if successful + * -1 if failed + */ + +static int set_dos_name(ntfs_inode *ni, ntfs_inode *dir_ni, + ntfschar *shortname, int shortlen, + ntfschar *longname, int longlen, + ntfschar *deletename, int deletelen, BOOL existed) +{ + unsigned int linkcount; + ntfs_volume *vol; + BOOL collapsible; + BOOL deleted; + BOOL done; + FILE_NAME_TYPE_FLAGS oldnametype; + u64 dnum; + u64 fnum; + int res; + + res = -1; + vol = ni->vol; + dnum = dir_ni->mft_no; + fnum = ni->mft_no; + /* save initial link count */ + linkcount = le16_to_cpu(ni->mrec->link_count); + + /* check whether the same name may be used as DOS and WIN32 */ + collapsible = ntfs_collapsible_chars(ni->vol, shortname, shortlen, + longname, longlen); + if (collapsible) { + deleted = FALSE; + done = FALSE; + if (existed) { + oldnametype = set_namespace(ni, dir_ni, deletename, + deletelen, FILE_NAME_POSIX); + if (oldnametype == FILE_NAME_DOS) { + if (set_namespace(ni, dir_ni, longname, longlen, + FILE_NAME_WIN32_AND_DOS) >= 0) { + if (!ntfs_delete(vol, + (const char*)NULL, ni, dir_ni, + deletename, deletelen)) + res = 0; + deleted = TRUE; + } else + done = TRUE; + } + } + if (!deleted) { + if (!done && (set_namespace(ni, dir_ni, + longname, longlen, + FILE_NAME_WIN32_AND_DOS) >= 0)) + res = 0; + ntfs_inode_update_times(ni, NTFS_UPDATE_CTIME); + ntfs_inode_update_times(dir_ni, NTFS_UPDATE_MCTIME); + if (ntfs_inode_close_in_dir(ni,dir_ni) && !res) + res = -1; + if (ntfs_inode_close(dir_ni) && !res) + res = -1; + } + } else { + if (!ntfs_link_i(ni, dir_ni, shortname, shortlen, + FILE_NAME_DOS) + /* make sure a new link was recorded */ + && (le16_to_cpu(ni->mrec->link_count) > linkcount)) { + /* delete the existing long name or short name */ +// is it ok to not provide the path ? + if (!ntfs_delete(vol, (char*)NULL, ni, dir_ni, + deletename, deletelen)) { + /* delete closes the inodes, so have to open again */ + dir_ni = ntfs_inode_open(vol, dnum); + if (dir_ni) { + ni = ntfs_inode_open(vol, fnum); + if (ni) { + if (!ntfs_link_i(ni, dir_ni, + longname, longlen, + FILE_NAME_WIN32)) + res = 0; + if (ntfs_inode_close_in_dir(ni, + dir_ni) + && !res) + res = -1; + } + if (ntfs_inode_close(dir_ni) && !res) + res = -1; + } + } + } else { + ntfs_inode_close_in_dir(ni,dir_ni); + ntfs_inode_close(dir_ni); + } + } + return (res); +} + + +/* + * Set the ntfs DOS name into an extended attribute + * + * The DOS name will be added as another file name attribute + * using the existing file name information from the original + * name or overwriting the DOS Name if one exists. + * + * The inode of the file is always closed + */ + +int ntfs_set_ntfs_dos_name(ntfs_inode *ni, ntfs_inode *dir_ni, + const char *value, size_t size, int flags) +{ + int res = 0; + int longlen = 0; + int shortlen = 0; + char newname[MAX_DOS_NAME_LENGTH + 1]; + ntfschar oldname[MAX_DOS_NAME_LENGTH]; + int oldlen; + ntfs_volume *vol; + u64 fnum; + u64 dnum; + BOOL closed = FALSE; + ntfschar *shortname = NULL; + ntfschar longname[NTFS_MAX_NAME_LEN]; + + vol = ni->vol; + fnum = ni->mft_no; + /* convert the string to the NTFS wide chars */ + if (size > MAX_DOS_NAME_LENGTH) + size = MAX_DOS_NAME_LENGTH; + strncpy(newname, value, size); + newname[size] = 0; + shortlen = ntfs_mbstoucs(newname, &shortname); + /* make sure the short name has valid chars */ + if ((shortlen < 0) || ntfs_forbidden_chars(shortname,shortlen)) { + ntfs_inode_close_in_dir(ni,dir_ni); + ntfs_inode_close(dir_ni); + res = -errno; + return res; + } + dnum = dir_ni->mft_no; + longlen = get_long_name(ni, dnum, longname); + if (longlen > 0) { + oldlen = get_dos_name(ni, dnum, oldname); + if ((oldlen >= 0) + && !ntfs_forbidden_chars(longname, longlen)) { + if (oldlen > 0) { + if (flags & XATTR_CREATE) { + res = -1; + errno = EEXIST; + } else + if ((shortlen == oldlen) + && !memcmp(shortname,oldname, + oldlen*sizeof(ntfschar))) + /* already set, done */ + res = 0; + else { + res = set_dos_name(ni, dir_ni, + shortname, shortlen, + longname, longlen, + oldname, oldlen, TRUE); + closed = TRUE; + } + } else { + if (flags & XATTR_REPLACE) { + res = -1; + errno = ENODATA; + } else { + res = set_dos_name(ni, dir_ni, + shortname, shortlen, + longname, longlen, + longname, longlen, FALSE); + closed = TRUE; + } + } + } else + res = -1; + } else { + res = -1; + errno = ENOENT; + } + free(shortname); + if (!closed) { + ntfs_inode_close_in_dir(ni,dir_ni); + ntfs_inode_close(dir_ni); + } + return (res ? -1 : 0); +} + +/* + * Delete the ntfs DOS name + */ + +int ntfs_remove_ntfs_dos_name(ntfs_inode *ni, ntfs_inode *dir_ni) +{ + int res; + int oldnametype; + int longlen = 0; + int shortlen; + u64 dnum; + ntfs_volume *vol; + BOOL deleted = FALSE; + ntfschar shortname[MAX_DOS_NAME_LENGTH]; + ntfschar longname[NTFS_MAX_NAME_LEN]; + + res = -1; + vol = ni->vol; + dnum = dir_ni->mft_no; + longlen = get_long_name(ni, dnum, longname); + if (longlen > 0) { + shortlen = get_dos_name(ni, dnum, shortname); + if (shortlen >= 0) { + /* migrate the long name as Posix */ + oldnametype = set_namespace(ni,dir_ni,longname,longlen, + FILE_NAME_POSIX); + switch (oldnametype) { + case FILE_NAME_WIN32_AND_DOS : + /* name was Win32+DOS : done */ + res = 0; + break; + case FILE_NAME_DOS : + /* name was DOS, make it back to DOS */ + set_namespace(ni,dir_ni,longname,longlen, + FILE_NAME_DOS); + errno = ENOENT; + break; + case FILE_NAME_WIN32 : + /* name was Win32, make it Posix and delete */ + if (set_namespace(ni,dir_ni,shortname,shortlen, + FILE_NAME_POSIX) >= 0) { + if (!ntfs_delete(vol, + (const char*)NULL, ni, + dir_ni, shortname, + shortlen)) + res = 0; + deleted = TRUE; + } else { + /* + * DOS name has been found, but cannot + * migrate to Posix : something bad + * has happened + */ + errno = EIO; + ntfs_log_error("Could not change" + " DOS name of inode %lld to Posix\n", + (long long)ni->mft_no); + } + break; + default : + /* name was Posix or not found : error */ + errno = ENOENT; + break; + } + } + } else { + errno = ENOENT; + res = -1; + } + if (!deleted) { + ntfs_inode_close_in_dir(ni,dir_ni); + ntfs_inode_close(dir_ni); + } + return (res); +} + +#endif diff --git a/libntfs-3g/efs.c b/libntfs-3g/efs.c new file mode 100755 index 0000000..0af1a4d --- a/dev/null +++ b/libntfs-3g/efs.c @@ -0,0 +1,346 @@ +/** + * efs.c - Limited processing of encrypted files + * + * This module is part of ntfs-3g library + * + * Copyright (c) 2009 Martin Bene + * Copyright (c) 2009 Jean-Pierre Andre + * + * This program/include file 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/include file 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 (in the main directory of the NTFS-3G + * distribution in the file COPYING); if not, write to the Free Software + * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_ERRNO_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_SYS_STAT_H +#include +#endif + +#ifdef HAVE_SETXATTR +#include +#endif + +#ifdef HAVE_SYS_SYSMACROS_H +#include +#endif + +#include "types.h" +#include "debug.h" +#include "attrib.h" +#include "inode.h" +#include "dir.h" +#include "efs.h" +#include "index.h" +#include "logging.h" +#include "misc.h" +#include "efs.h" + +#ifdef HAVE_SETXATTR /* extended attributes interface required */ + +static ntfschar logged_utility_stream_name[] = { + const_cpu_to_le16('$'), + const_cpu_to_le16('E'), + const_cpu_to_le16('F'), + const_cpu_to_le16('S'), + const_cpu_to_le16(0) +} ; + + +/* + * Get the ntfs EFS info into an extended attribute + */ + +int ntfs_get_efs_info(ntfs_inode *ni, char *value, size_t size) +{ + EFS_ATTR_HEADER *efs_info; + s64 attr_size = 0; + + if (ni) { + if (ni->flags & FILE_ATTR_ENCRYPTED) { + efs_info = (EFS_ATTR_HEADER*)ntfs_attr_readall(ni, + AT_LOGGED_UTILITY_STREAM,(ntfschar*)NULL, 0, + &attr_size); + if (efs_info + && (le32_to_cpu(efs_info->length) == attr_size)) { + if (attr_size <= (s64)size) { + if (value) + memcpy(value,efs_info,attr_size); + else { + errno = EFAULT; + attr_size = 0; + } + } else + if (size) { + errno = ERANGE; + attr_size = 0; + } + free (efs_info); + } else { + if (efs_info) { + free(efs_info); + ntfs_log_error("Bad efs_info for inode %lld\n", + (long long)ni->mft_no); + } else { + ntfs_log_error("Could not get efsinfo" + " for inode %lld\n", + (long long)ni->mft_no); + } + errno = EIO; + attr_size = 0; + } + } else { + errno = ENODATA; + ntfs_log_trace("Inode %lld is not encrypted\n", + (long long)ni->mft_no); + } + } + return (attr_size ? (int)attr_size : -errno); +} + +/* + * Set the efs data from an extended attribute + * Warning : the new data is not checked + * Returns 0, or -1 if there is a problem + */ + +int ntfs_set_efs_info(ntfs_inode *ni, const char *value, size_t size, + int flags) + +{ + int res; + int written; + ntfs_attr *na; + const EFS_ATTR_HEADER *info_header; + ntfs_attr_search_ctx *ctx; + + res = 0; + if (ni && value && size) { + if (ni->flags & (FILE_ATTR_ENCRYPTED | FILE_ATTR_COMPRESSED)) { + if (ni->flags & FILE_ATTR_ENCRYPTED) { + ntfs_log_trace("Inode %lld already encrypted\n", + (long long)ni->mft_no); + errno = EEXIST; + } else { + /* + * Possible problem : if encrypted file was + * restored in a compressed directory, it was + * restored as compressed. + * TODO : decompress first. + */ + ntfs_log_error("Inode %lld cannot be encrypted and compressed\n", + (long long)ni->mft_no); + errno = EIO; + } + return -1; + } + info_header = (const EFS_ATTR_HEADER*)value; + /* make sure we get a likely efsinfo */ + if (le32_to_cpu(info_header->length) != size) { + errno = EINVAL; + return (-1); + } + if (!ntfs_attr_exist(ni,AT_LOGGED_UTILITY_STREAM, + (ntfschar*)NULL,0)) { + if (!(flags & XATTR_REPLACE)) { + /* + * no logged_utility_stream attribute : add one, + * apparently, this does not feed the new value in + */ + res = ntfs_attr_add(ni,AT_LOGGED_UTILITY_STREAM, + logged_utility_stream_name,4, + (u8*)NULL,(s64)size); + } else { + errno = ENODATA; + res = -1; + } + } else { + errno = EEXIST; + res = -1; + } + if (!res) { + /* + * open and update the existing efs data + */ + na = ntfs_attr_open(ni, AT_LOGGED_UTILITY_STREAM, + logged_utility_stream_name, 4); + if (na) { + /* resize attribute */ + res = ntfs_attr_truncate(na, (s64)size); + /* overwrite value if any */ + if (!res && value) { + written = (int)ntfs_attr_pwrite(na, + (s64)0, (s64)size, value); + if (written != (s64)size) { + ntfs_log_error("Failed to " + "update efs data\n"); + errno = EIO; + res = -1; + } + } + ntfs_attr_close(na); + } else + res = -1; + } + if (!res) { + /* Don't handle AT_DATA Attribute(s) if inode is a directory */ + if (!(ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)) { + /* iterate over AT_DATA attributes */ + /* set encrypted flag, truncate attribute to match padding bytes */ + + ctx = ntfs_attr_get_search_ctx(ni, NULL); + if (!ctx) { + ntfs_log_error("Failed to get ctx for efs\n"); + return (-1); + } + while (!ntfs_attr_lookup(AT_DATA, NULL, 0, + CASE_SENSITIVE, 0, NULL, 0, ctx)) { + if (ntfs_efs_fixup_attribute(ctx, NULL)) { + ntfs_log_error("Error in efs fixup of AT_DATA Attribute\n"); + ntfs_attr_put_search_ctx(ctx); + return(-1); + } + } + ntfs_attr_put_search_ctx(ctx); + } + ni->flags |= FILE_ATTR_ENCRYPTED; + NInoSetDirty(ni); + NInoFileNameSetDirty(ni); + } + } else { + errno = EINVAL; + res = -1; + } + return (res ? -1 : 0); +} + +/* + * Fixup raw encrypted AT_DATA Attribute + * read padding length from last two bytes + * truncate attribute, make non-resident, + * set data size to match padding length + * set ATTR_IS_ENCRYPTED flag on attribute + * + * Return 0 if successful + * -1 if failed (errno tells why) + */ + +int ntfs_efs_fixup_attribute(ntfs_attr_search_ctx *ctx, ntfs_attr *na) +{ + u64 newsize; + le16 appended_bytes; + u16 padding_length; + ATTR_RECORD *a; + ntfs_inode *ni; + BOOL close_na = FALSE; + BOOL close_ctx = FALSE; + + if (!ctx && !na) { + ntfs_log_error("neither ctx nor na specified for efs_fixup_attribute\n"); + goto err_out; + } + if (!ctx) { + ctx = ntfs_attr_get_search_ctx(na->ni, NULL); + if (!ctx) { + ntfs_log_error("Failed to get ctx for efs\n"); + goto err_out; + } + close_ctx=TRUE; + if (ntfs_attr_lookup(AT_DATA, na->name, na->name_len, + CASE_SENSITIVE, 0, NULL, 0, ctx)) { + ntfs_log_error("attr lookup for AT_DATA attribute failed in efs fixup\n"); + goto err_out; + } + } + + a = ctx->attr; + if (!na) { + na = ntfs_attr_open(ctx->ntfs_ino, AT_DATA, + (ntfschar*)((u8*)a + le16_to_cpu(a->name_offset)), + a->name_length); + if (!na) { + ntfs_log_error("can't open DATA Attribute\n"); + return (-1); + } + close_na = TRUE; + } + /* make sure size is valid for a raw encrypted stream */ + if ((na->data_size & 511) != 2) { + ntfs_log_error("Bad raw encrypted stream\n"); + goto err_out; + } + /* read padding length from last two bytes of attribute */ + if (ntfs_attr_pread(na, na->data_size-2, 2, &appended_bytes) != 2) { + ntfs_log_error("Error reading padding length\n"); + goto err_out; + } + padding_length = le16_to_cpu(appended_bytes); + if (padding_length > 511 || padding_length > na->data_size-2) { + errno = EINVAL; + ntfs_log_error("invalid padding length %d for data_size %lld\n", + padding_length, (long long)na->data_size); + goto err_out; + } + newsize = na->data_size - padding_length - 2; + /* truncate attribute to possibly free clusters allocated + for the last two bytes */ + if (ntfs_attr_truncate(na, na->data_size-2)) { + ntfs_log_error("Error truncating attribute\n"); + goto err_out; + } + + /* Encrypted AT_DATA Attributes MUST be non-resident */ + if (!NAttrNonResident(na) + && ntfs_attr_make_non_resident(na, ctx)) { + ntfs_log_error("Error making DATA attribute non-resident\n"); + goto err_out; + } + ni = na->ni; + if (!na->name_len) { + ni->data_size = newsize; + ni->allocated_size = na->allocated_size; + } + NInoSetDirty(ni); + NInoFileNameSetDirty(ni); + if (close_na) + ntfs_attr_close(na); + + ctx->attr->data_size = cpu_to_le64(newsize); + if (le64_to_cpu(ctx->attr->initialized_size) > newsize) + ctx->attr->initialized_size = ctx->attr->data_size; + ctx->attr->flags |= ATTR_IS_ENCRYPTED; + if (close_ctx) + ntfs_attr_put_search_ctx(ctx); + + return (0); +err_out: + if (close_na && na) + ntfs_attr_close(na); + if (close_ctx && ctx) + ntfs_attr_put_search_ctx(ctx); + return (-1); +} + +#endif /* HAVE_SETXATTR */ diff --git a/libntfs-3g/index.c b/libntfs-3g/index.c new file mode 100755 index 0000000..7df0dee --- a/dev/null +++ b/libntfs-3g/index.c @@ -0,0 +1,2063 @@ +/** + * index.c - NTFS index handling. Originated from the Linux-NTFS project. + * + * Copyright (c) 2004-2005 Anton Altaparmakov + * Copyright (c) 2004-2005 Richard Russon + * Copyright (c) 2005-2006 Yura Pakhuchiy + * Copyright (c) 2005-2008 Szabolcs Szakacsits + * Copyright (c) 2007 Jean-Pierre Andre + * + * This program/include file 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/include file 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 (in the main directory of the NTFS-3G + * distribution in the file COPYING); if not, write to the Free Software + * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_ERRNO_H +#include +#endif + +#include "attrib.h" +#include "debug.h" +#include "index.h" +#include "collate.h" +#include "mst.h" +#include "dir.h" +#include "logging.h" +#include "bitmap.h" +#include "reparse.h" +#include "misc.h" + +/** + * ntfs_index_entry_mark_dirty - mark an index entry dirty + * @ictx: ntfs index context describing the index entry + * + * Mark the index entry described by the index entry context @ictx dirty. + * + * If the index entry is in the index root attribute, simply mark the inode + * containing the index root attribute dirty. This ensures the mftrecord, and + * hence the index root attribute, will be written out to disk later. + * + * If the index entry is in an index block belonging to the index allocation + * attribute, set ib_dirty to TRUE, thus index block will be updated during + * ntfs_index_ctx_put. + */ +void ntfs_index_entry_mark_dirty(ntfs_index_context *ictx) +{ + if (ictx->is_in_root) + ntfs_inode_mark_dirty(ictx->actx->ntfs_ino); + else + ictx->ib_dirty = TRUE; +} + +static s64 ntfs_ib_vcn_to_pos(ntfs_index_context *icx, VCN vcn) +{ + return vcn << icx->vcn_size_bits; +} + +static VCN ntfs_ib_pos_to_vcn(ntfs_index_context *icx, s64 pos) +{ + return pos >> icx->vcn_size_bits; +} + +static int ntfs_ib_write(ntfs_index_context *icx, INDEX_BLOCK *ib) +{ + s64 ret, vcn = sle64_to_cpu(ib->index_block_vcn); + + ntfs_log_trace("vcn: %lld\n", (long long)vcn); + + ret = ntfs_attr_mst_pwrite(icx->ia_na, ntfs_ib_vcn_to_pos(icx, vcn), + 1, icx->block_size, ib); + if (ret != 1) { + ntfs_log_perror("Failed to write index block %lld, inode %llu", + (long long)vcn, (unsigned long long)icx->ni->mft_no); + return STATUS_ERROR; + } + + return STATUS_OK; +} + +static int ntfs_icx_ib_write(ntfs_index_context *icx) +{ + if (ntfs_ib_write(icx, icx->ib)) + return STATUS_ERROR; + + icx->ib_dirty = FALSE; + + return STATUS_OK; +} + +/** + * ntfs_index_ctx_get - allocate and initialize a new index context + * @ni: ntfs inode with which to initialize the context + * @name: name of the which context describes + * @name_len: length of the index name + * + * Allocate a new index context, initialize it with @ni and return it. + * Return NULL if allocation failed. + */ +ntfs_index_context *ntfs_index_ctx_get(ntfs_inode *ni, + ntfschar *name, u32 name_len) +{ + ntfs_index_context *icx; + + ntfs_log_trace("Entering\n"); + + if (!ni) { + errno = EINVAL; + return NULL; + } + if (ni->nr_extents == -1) + ni = ni->base_ni; + icx = ntfs_calloc(sizeof(ntfs_index_context)); + if (icx) + *icx = (ntfs_index_context) { + .ni = ni, + .name = name, + .name_len = name_len, + }; + return icx; +} + +static void ntfs_index_ctx_free(ntfs_index_context *icx) +{ + ntfs_log_trace("Entering\n"); + + if (!icx->entry) + return; + + if (icx->actx) + ntfs_attr_put_search_ctx(icx->actx); + + if (!icx->is_in_root) { + if (icx->ib_dirty) { + /* FIXME: Error handling!!! */ + ntfs_ib_write(icx, icx->ib); + } + free(icx->ib); + } + + ntfs_attr_close(icx->ia_na); +} + +/** + * ntfs_index_ctx_put - release an index context + * @icx: index context to free + * + * Release the index context @icx, releasing all associated resources. + */ +void ntfs_index_ctx_put(ntfs_index_context *icx) +{ + ntfs_index_ctx_free(icx); + free(icx); +} + +/** + * ntfs_index_ctx_reinit - reinitialize an index context + * @icx: index context to reinitialize + * + * Reinitialize the index context @icx so it can be used for ntfs_index_lookup. + */ +void ntfs_index_ctx_reinit(ntfs_index_context *icx) +{ + ntfs_log_trace("Entering\n"); + + ntfs_index_ctx_free(icx); + + *icx = (ntfs_index_context) { + .ni = icx->ni, + .name = icx->name, + .name_len = icx->name_len, + }; +} + +static VCN *ntfs_ie_get_vcn_addr(INDEX_ENTRY *ie) +{ + return (VCN *)((u8 *)ie + le16_to_cpu(ie->length) - sizeof(VCN)); +} + +/** + * Get the subnode vcn to which the index entry refers. + */ +VCN ntfs_ie_get_vcn(INDEX_ENTRY *ie) +{ + return sle64_to_cpup(ntfs_ie_get_vcn_addr(ie)); +} + +static INDEX_ENTRY *ntfs_ie_get_first(INDEX_HEADER *ih) +{ + return (INDEX_ENTRY *)((u8 *)ih + le32_to_cpu(ih->entries_offset)); +} + +static INDEX_ENTRY *ntfs_ie_get_next(INDEX_ENTRY *ie) +{ + return (INDEX_ENTRY *)((char *)ie + le16_to_cpu(ie->length)); +} + +static u8 *ntfs_ie_get_end(INDEX_HEADER *ih) +{ + /* FIXME: check if it isn't overflowing the index block size */ + return (u8 *)ih + le32_to_cpu(ih->index_length); +} + +static int ntfs_ie_end(INDEX_ENTRY *ie) +{ + return ie->ie_flags & INDEX_ENTRY_END || !ie->length; +} + +/** + * Find the last entry in the index block + */ +static INDEX_ENTRY *ntfs_ie_get_last(INDEX_ENTRY *ie, char *ies_end) +{ + ntfs_log_trace("Entering\n"); + + while ((char *)ie < ies_end && !ntfs_ie_end(ie)) + ie = ntfs_ie_get_next(ie); + + return ie; +} + +static INDEX_ENTRY *ntfs_ie_get_by_pos(INDEX_HEADER *ih, int pos) +{ + INDEX_ENTRY *ie; + + ntfs_log_trace("pos: %d\n", pos); + + ie = ntfs_ie_get_first(ih); + + while (pos-- > 0) + ie = ntfs_ie_get_next(ie); + + return ie; +} + +static INDEX_ENTRY *ntfs_ie_prev(INDEX_HEADER *ih, INDEX_ENTRY *ie) +{ + INDEX_ENTRY *ie_prev = NULL; + INDEX_ENTRY *tmp; + + ntfs_log_trace("Entering\n"); + + tmp = ntfs_ie_get_first(ih); + + while (tmp != ie) { + ie_prev = tmp; + tmp = ntfs_ie_get_next(tmp); + } + + return ie_prev; +} + +char *ntfs_ie_filename_get(INDEX_ENTRY *ie) +{ + FILE_NAME_ATTR *fn; + + fn = (FILE_NAME_ATTR *)&ie->key; + return ntfs_attr_name_get(fn->file_name, fn->file_name_length); +} + +void ntfs_ie_filename_dump(INDEX_ENTRY *ie) +{ + char *s; + + s = ntfs_ie_filename_get(ie); + ntfs_log_debug("'%s' ", s); + ntfs_attr_name_free(&s); +} + +void ntfs_ih_filename_dump(INDEX_HEADER *ih) +{ + INDEX_ENTRY *ie; + + ntfs_log_trace("Entering\n"); + + ie = ntfs_ie_get_first(ih); + while (!ntfs_ie_end(ie)) { + ntfs_ie_filename_dump(ie); + ie = ntfs_ie_get_next(ie); + } +} + +static int ntfs_ih_numof_entries(INDEX_HEADER *ih) +{ + int n; + INDEX_ENTRY *ie; + u8 *end; + + ntfs_log_trace("Entering\n"); + + end = ntfs_ie_get_end(ih); + ie = ntfs_ie_get_first(ih); + for (n = 0; !ntfs_ie_end(ie) && (u8 *)ie < end; n++) + ie = ntfs_ie_get_next(ie); + return n; +} + +static int ntfs_ih_one_entry(INDEX_HEADER *ih) +{ + return (ntfs_ih_numof_entries(ih) == 1); +} + +static int ntfs_ih_zero_entry(INDEX_HEADER *ih) +{ + return (ntfs_ih_numof_entries(ih) == 0); +} + +static void ntfs_ie_delete(INDEX_HEADER *ih, INDEX_ENTRY *ie) +{ + u32 new_size; + + ntfs_log_trace("Entering\n"); + + new_size = le32_to_cpu(ih->index_length) - le16_to_cpu(ie->length); + ih->index_length = cpu_to_le32(new_size); + memmove(ie, (u8 *)ie + le16_to_cpu(ie->length), + new_size - ((u8 *)ie - (u8 *)ih)); +} + +static void ntfs_ie_set_vcn(INDEX_ENTRY *ie, VCN vcn) +{ + *ntfs_ie_get_vcn_addr(ie) = cpu_to_le64(vcn); +} + +/** + * Insert @ie index entry at @pos entry. Used @ih values should be ok already. + */ +static void ntfs_ie_insert(INDEX_HEADER *ih, INDEX_ENTRY *ie, INDEX_ENTRY *pos) +{ + int ie_size = le16_to_cpu(ie->length); + + ntfs_log_trace("Entering\n"); + + ih->index_length = cpu_to_le32(le32_to_cpu(ih->index_length) + ie_size); + memmove((u8 *)pos + ie_size, pos, + le32_to_cpu(ih->index_length) - ((u8 *)pos - (u8 *)ih) - ie_size); + memcpy(pos, ie, ie_size); +} + +static INDEX_ENTRY *ntfs_ie_dup(INDEX_ENTRY *ie) +{ + INDEX_ENTRY *dup; + + ntfs_log_trace("Entering\n"); + + dup = ntfs_malloc(le16_to_cpu(ie->length)); + if (dup) + memcpy(dup, ie, le16_to_cpu(ie->length)); + + return dup; +} + +static INDEX_ENTRY *ntfs_ie_dup_novcn(INDEX_ENTRY *ie) +{ + INDEX_ENTRY *dup; + int size = le16_to_cpu(ie->length); + + ntfs_log_trace("Entering\n"); + + if (ie->ie_flags & INDEX_ENTRY_NODE) + size -= sizeof(VCN); + + dup = ntfs_malloc(size); + if (dup) { + memcpy(dup, ie, size); + dup->ie_flags &= ~INDEX_ENTRY_NODE; + dup->length = cpu_to_le16(size); + } + return dup; +} + +static int ntfs_ia_check(ntfs_index_context *icx, INDEX_BLOCK *ib, VCN vcn) +{ + u32 ib_size = (unsigned)le32_to_cpu(ib->index.allocated_size) + 0x18; + + ntfs_log_trace("Entering\n"); + + if (!ntfs_is_indx_record(ib->magic)) { + + ntfs_log_error("Corrupt index block signature: vcn %lld inode " + "%llu\n", (long long)vcn, + (unsigned long long)icx->ni->mft_no); + return -1; + } + + if (sle64_to_cpu(ib->index_block_vcn) != vcn) { + + ntfs_log_error("Corrupt index block: VCN (%lld) is different " + "from expected VCN (%lld) in inode %llu\n", + (long long)sle64_to_cpu(ib->index_block_vcn), + (long long)vcn, + (unsigned long long)icx->ni->mft_no); + return -1; + } + + if (ib_size != icx->block_size) { + + ntfs_log_error("Corrupt index block : VCN (%lld) of inode %llu " + "has a size (%u) differing from the index " + "specified size (%u)\n", (long long)vcn, + (unsigned long long)icx->ni->mft_no, ib_size, + icx->block_size); + return -1; + } + return 0; +} + +static INDEX_ROOT *ntfs_ir_lookup(ntfs_inode *ni, ntfschar *name, + u32 name_len, ntfs_attr_search_ctx **ctx) +{ + ATTR_RECORD *a; + INDEX_ROOT *ir = NULL; + + ntfs_log_trace("Entering\n"); + + *ctx = ntfs_attr_get_search_ctx(ni, NULL); + if (!*ctx) + return NULL; + + if (ntfs_attr_lookup(AT_INDEX_ROOT, name, name_len, CASE_SENSITIVE, + 0, NULL, 0, *ctx)) { + ntfs_log_perror("Failed to lookup $INDEX_ROOT"); + goto err_out; + } + + a = (*ctx)->attr; + if (a->non_resident) { + errno = EINVAL; + ntfs_log_perror("Non-resident $INDEX_ROOT detected"); + goto err_out; + } + + ir = (INDEX_ROOT *)((char *)a + le16_to_cpu(a->value_offset)); +err_out: + if (!ir) { + ntfs_attr_put_search_ctx(*ctx); + *ctx = NULL; + } + return ir; +} + +static INDEX_ROOT *ntfs_ir_lookup2(ntfs_inode *ni, ntfschar *name, u32 len) +{ + ntfs_attr_search_ctx *ctx; + INDEX_ROOT *ir; + + ir = ntfs_ir_lookup(ni, name, len, &ctx); + if (ir) + ntfs_attr_put_search_ctx(ctx); + return ir; +} + +/** + * Find a key in the index block. + * + * Return values: + * STATUS_OK with errno set to ESUCCESS if we know for sure that the + * entry exists and @ie_out points to this entry. + * STATUS_NOT_FOUND with errno set to ENOENT if we know for sure the + * entry doesn't exist and @ie_out is the insertion point. + * STATUS_KEEP_SEARCHING if we can't answer the above question and + * @vcn will contain the node index block. + * STATUS_ERROR with errno set if on unexpected error during lookup. + */ +static int ntfs_ie_lookup(const void *key, const int key_len, + ntfs_index_context *icx, INDEX_HEADER *ih, + VCN *vcn, INDEX_ENTRY **ie_out) +{ + INDEX_ENTRY *ie; + u8 *index_end; + int rc, item = 0; + + ntfs_log_trace("Entering\n"); + + index_end = ntfs_ie_get_end(ih); + + /* + * Loop until we exceed valid memory (corruption case) or until we + * reach the last entry. + */ + for (ie = ntfs_ie_get_first(ih); ; ie = ntfs_ie_get_next(ie)) { + /* Bounds checks. */ + if ((u8 *)ie + sizeof(INDEX_ENTRY_HEADER) > index_end || + (u8 *)ie + le16_to_cpu(ie->length) > index_end) { + errno = ERANGE; + ntfs_log_error("Index entry out of bounds in inode " + "%llu.\n", + (unsigned long long)icx->ni->mft_no); + return STATUS_ERROR; + } + /* + * The last entry cannot contain a key. It can however contain + * a pointer to a child node in the B+tree so we just break out. + */ + if (ntfs_ie_end(ie)) + break; + /* + * Not a perfect match, need to do full blown collation so we + * know which way in the B+tree we have to go. + */ + if (!icx->collate) { + ntfs_log_error("Collation function not defined\n"); + errno = EOPNOTSUPP; + return STATUS_ERROR; + } + rc = icx->collate(icx->ni->vol, key, key_len, + &ie->key, le16_to_cpu(ie->key_length)); + if (rc == NTFS_COLLATION_ERROR) { + ntfs_log_error("Collation error. Perhaps a filename " + "contains invalid characters?\n"); + errno = ERANGE; + return STATUS_ERROR; + } + /* + * If @key collates before the key of the current entry, there + * is definitely no such key in this index but we might need to + * descend into the B+tree so we just break out of the loop. + */ + if (rc == -1) + break; + + if (!rc) { + *ie_out = ie; + errno = 0; + icx->parent_pos[icx->pindex] = item; + return STATUS_OK; + } + + item++; + } + /* + * We have finished with this index block without success. Check for the + * presence of a child node and if not present return with errno ENOENT, + * otherwise we will keep searching in another index block. + */ + if (!(ie->ie_flags & INDEX_ENTRY_NODE)) { + ntfs_log_debug("Index entry wasn't found.\n"); + *ie_out = ie; + errno = ENOENT; + return STATUS_NOT_FOUND; + } + + /* Get the starting vcn of the index_block holding the child node. */ + *vcn = ntfs_ie_get_vcn(ie); + if (*vcn < 0) { + errno = EINVAL; + ntfs_log_perror("Negative vcn in inode %llu", + (unsigned long long)icx->ni->mft_no); + return STATUS_ERROR; + } + + ntfs_log_trace("Parent entry number %d\n", item); + icx->parent_pos[icx->pindex] = item; + + return STATUS_KEEP_SEARCHING; +} + +static ntfs_attr *ntfs_ia_open(ntfs_index_context *icx, ntfs_inode *ni) +{ + ntfs_attr *na; + + na = ntfs_attr_open(ni, AT_INDEX_ALLOCATION, icx->name, icx->name_len); + if (!na) { + ntfs_log_perror("Failed to open index allocation of inode " + "%llu", (unsigned long long)ni->mft_no); + return NULL; + } + + return na; +} + +static int ntfs_ib_read(ntfs_index_context *icx, VCN vcn, INDEX_BLOCK *dst) +{ + s64 pos, ret; + + ntfs_log_trace("vcn: %lld\n", (long long)vcn); + + pos = ntfs_ib_vcn_to_pos(icx, vcn); + + ret = ntfs_attr_mst_pread(icx->ia_na, pos, 1, icx->block_size, (u8 *)dst); + if (ret != 1) { + if (ret == -1) + ntfs_log_perror("Failed to read index block"); + else + ntfs_log_error("Failed to read full index block at " + "%lld\n", (long long)pos); + return -1; + } + + if (ntfs_ia_check(icx, dst, vcn)) + return -1; + + return 0; +} + +static int ntfs_icx_parent_inc(ntfs_index_context *icx) +{ + icx->pindex++; + if (icx->pindex >= MAX_PARENT_VCN) { + errno = EOPNOTSUPP; + ntfs_log_perror("Index is over %d level deep", MAX_PARENT_VCN); + return STATUS_ERROR; + } + return STATUS_OK; +} + +static int ntfs_icx_parent_dec(ntfs_index_context *icx) +{ + icx->pindex--; + if (icx->pindex < 0) { + errno = EINVAL; + ntfs_log_perror("Corrupt index pointer (%d)", icx->pindex); + return STATUS_ERROR; + } + return STATUS_OK; +} + +/** + * ntfs_index_lookup - find a key in an index and return its index entry + * @key: [IN] key for which to search in the index + * @key_len: [IN] length of @key in bytes + * @icx: [IN/OUT] context describing the index and the returned entry + * + * Before calling ntfs_index_lookup(), @icx must have been obtained from a + * call to ntfs_index_ctx_get(). + * + * Look for the @key in the index specified by the index lookup context @icx. + * ntfs_index_lookup() walks the contents of the index looking for the @key. + * + * If the @key is found in the index, 0 is returned and @icx is setup to + * describe the index entry containing the matching @key. @icx->entry is the + * index entry and @icx->data and @icx->data_len are the index entry data and + * its length in bytes, respectively. + * + * If the @key is not found in the index, -1 is returned, errno = ENOENT and + * @icx is setup to describe the index entry whose key collates immediately + * after the search @key, i.e. this is the position in the index at which + * an index entry with a key of @key would need to be inserted. + * + * If an error occurs return -1, set errno to error code and @icx is left + * untouched. + * + * When finished with the entry and its data, call ntfs_index_ctx_put() to free + * the context and other associated resources. + * + * If the index entry was modified, call ntfs_index_entry_mark_dirty() before + * the call to ntfs_index_ctx_put() to ensure that the changes are written + * to disk. + */ +int ntfs_index_lookup(const void *key, const int key_len, ntfs_index_context *icx) +{ + VCN old_vcn, vcn; + ntfs_inode *ni = icx->ni; + INDEX_ROOT *ir; + INDEX_ENTRY *ie; + INDEX_BLOCK *ib = NULL; + int ret, err = 0; + + ntfs_log_trace("Entering\n"); + + if (!key || key_len <= 0) { + errno = EINVAL; + ntfs_log_perror("key: %p key_len: %d", key, key_len); + return -1; + } + + ir = ntfs_ir_lookup(ni, icx->name, icx->name_len, &icx->actx); + if (!ir) { + if (errno == ENOENT) + errno = EIO; + return -1; + } + + icx->block_size = le32_to_cpu(ir->index_block_size); + if (icx->block_size < NTFS_BLOCK_SIZE) { + errno = EINVAL; + ntfs_log_perror("Index block size (%d) is smaller than the " + "sector size (%d)", icx->block_size, NTFS_BLOCK_SIZE); + goto err_out; + } + + if (ni->vol->cluster_size <= icx->block_size) + icx->vcn_size_bits = ni->vol->cluster_size_bits; + else + icx->vcn_size_bits = ni->vol->sector_size_bits; + /* get the appropriate collation function */ + icx->collate = ntfs_get_collate_function(ir->collation_rule); + if (!icx->collate) { + err = errno = EOPNOTSUPP; + ntfs_log_perror("Unknown collation rule 0x%x", + (unsigned)le32_to_cpu(ir->collation_rule)); + goto err_out; + } + + old_vcn = VCN_INDEX_ROOT_PARENT; + /* + * FIXME: check for both ir and ib that the first index entry is + * within the index block. + */ + ret = ntfs_ie_lookup(key, key_len, icx, &ir->index, &vcn, &ie); + if (ret == STATUS_ERROR) { + err = errno; + goto err_out; + } + + icx->ir = ir; + + if (ret != STATUS_KEEP_SEARCHING) { + /* STATUS_OK or STATUS_NOT_FOUND */ + err = errno; + icx->is_in_root = TRUE; + icx->parent_vcn[icx->pindex] = old_vcn; + goto done; + } + + /* Child node present, descend into it. */ + + icx->ia_na = ntfs_ia_open(icx, ni); + if (!icx->ia_na) + goto err_out; + + ib = ntfs_malloc(icx->block_size); + if (!ib) { + err = errno; + goto err_out; + } + +descend_into_child_node: + + icx->parent_vcn[icx->pindex] = old_vcn; + if (ntfs_icx_parent_inc(icx)) { + err = errno; + goto err_out; + } + old_vcn = vcn; + + ntfs_log_debug("Descend into node with VCN %lld\n", (long long)vcn); + + if (ntfs_ib_read(icx, vcn, ib)) + goto err_out; + + ret = ntfs_ie_lookup(key, key_len, icx, &ib->index, &vcn, &ie); + if (ret != STATUS_KEEP_SEARCHING) { + err = errno; + if (ret == STATUS_ERROR) + goto err_out; + + /* STATUS_OK or STATUS_NOT_FOUND */ + icx->is_in_root = FALSE; + icx->ib = ib; + icx->parent_vcn[icx->pindex] = vcn; + goto done; + } + + if ((ib->index.ih_flags & NODE_MASK) == LEAF_NODE) { + ntfs_log_error("Index entry with child node found in a leaf " + "node in inode 0x%llx.\n", + (unsigned long long)ni->mft_no); + goto err_out; + } + + goto descend_into_child_node; +err_out: + free(ib); + if (!err) + err = EIO; + errno = err; + return -1; +done: + icx->entry = ie; + icx->data = (u8 *)ie + offsetof(INDEX_ENTRY, key); + icx->data_len = le16_to_cpu(ie->key_length); + ntfs_log_trace("Done.\n"); + if (err) { + errno = err; + return -1; + } + return 0; + +} + +static INDEX_BLOCK *ntfs_ib_alloc(VCN ib_vcn, u32 ib_size, + INDEX_HEADER_FLAGS node_type) +{ + INDEX_BLOCK *ib; + int ih_size = sizeof(INDEX_HEADER); + + ntfs_log_trace("ib_vcn: %lld ib_size: %u\n", (long long)ib_vcn, ib_size); + + ib = ntfs_calloc(ib_size); + if (!ib) + return NULL; + + ib->magic = magic_INDX; + ib->usa_ofs = cpu_to_le16(sizeof(INDEX_BLOCK)); + ib->usa_count = cpu_to_le16(ib_size / NTFS_BLOCK_SIZE + 1); + /* Set USN to 1 */ + *(u16 *)((char *)ib + le16_to_cpu(ib->usa_ofs)) = cpu_to_le16(1); + ib->lsn = cpu_to_le64(0); + + ib->index_block_vcn = cpu_to_sle64(ib_vcn); + + ib->index.entries_offset = cpu_to_le32((ih_size + + le16_to_cpu(ib->usa_count) * 2 + 7) & ~7); + ib->index.index_length = 0; + ib->index.allocated_size = cpu_to_le32(ib_size - + (sizeof(INDEX_BLOCK) - ih_size)); + ib->index.ih_flags = node_type; + + return ib; +} + +/** + * Find the median by going through all the entries + */ +static INDEX_ENTRY *ntfs_ie_get_median(INDEX_HEADER *ih) +{ + INDEX_ENTRY *ie, *ie_start; + u8 *ie_end; + int i = 0, median; + + ntfs_log_trace("Entering\n"); + + ie = ie_start = ntfs_ie_get_first(ih); + ie_end = (u8 *)ntfs_ie_get_end(ih); + + while ((u8 *)ie < ie_end && !ntfs_ie_end(ie)) { + ie = ntfs_ie_get_next(ie); + i++; + } + /* + * NOTE: this could be also the entry at the half of the index block. + */ + median = i / 2 - 1; + + ntfs_log_trace("Entries: %d median: %d\n", i, median); + + for (i = 0, ie = ie_start; i <= median; i++) + ie = ntfs_ie_get_next(ie); + + return ie; +} + +static s64 ntfs_ibm_vcn_to_pos(ntfs_index_context *icx, VCN vcn) +{ + return ntfs_ib_vcn_to_pos(icx, vcn) / icx->block_size; +} + +static s64 ntfs_ibm_pos_to_vcn(ntfs_index_context *icx, s64 pos) +{ + return ntfs_ib_pos_to_vcn(icx, pos * icx->block_size); +} + +static int ntfs_ibm_add(ntfs_index_context *icx) +{ + u8 bmp[8]; + + ntfs_log_trace("Entering\n"); + + if (ntfs_attr_exist(icx->ni, AT_BITMAP, icx->name, icx->name_len)) + return STATUS_OK; + /* + * AT_BITMAP must be at least 8 bytes. + */ + memset(bmp, 0, sizeof(bmp)); + if (ntfs_attr_add(icx->ni, AT_BITMAP, icx->name, icx->name_len, + bmp, sizeof(bmp))) { + ntfs_log_perror("Failed to add AT_BITMAP"); + return STATUS_ERROR; + } + + return STATUS_OK; +} + +static int ntfs_ibm_modify(ntfs_index_context *icx, VCN vcn, int set) +{ + u8 byte; + s64 pos = ntfs_ibm_vcn_to_pos(icx, vcn); + u32 bpos = pos / 8; + u32 bit = 1 << (pos % 8); + ntfs_attr *na; + int ret = STATUS_ERROR; + + ntfs_log_trace("%s vcn: %lld\n", set ? "set" : "clear", (long long)vcn); + + na = ntfs_attr_open(icx->ni, AT_BITMAP, icx->name, icx->name_len); + if (!na) { + ntfs_log_perror("Failed to open $BITMAP attribute"); + return -1; + } + + if (set) { + if (na->data_size < bpos + 1) { + if (ntfs_attr_truncate(na, (na->data_size + 8) & ~7)) { + ntfs_log_perror("Failed to truncate AT_BITMAP"); + goto err_na; + } + } + } + + if (ntfs_attr_pread(na, bpos, 1, &byte) != 1) { + ntfs_log_perror("Failed to read $BITMAP"); + goto err_na; + } + + if (set) + byte |= bit; + else + byte &= ~bit; + + if (ntfs_attr_pwrite(na, bpos, 1, &byte) != 1) { + ntfs_log_perror("Failed to write $Bitmap"); + goto err_na; + } + + ret = STATUS_OK; +err_na: + ntfs_attr_close(na); + return ret; +} + + +static int ntfs_ibm_set(ntfs_index_context *icx, VCN vcn) +{ + return ntfs_ibm_modify(icx, vcn, 1); +} + +static int ntfs_ibm_clear(ntfs_index_context *icx, VCN vcn) +{ + return ntfs_ibm_modify(icx, vcn, 0); +} + +static VCN ntfs_ibm_get_free(ntfs_index_context *icx) +{ + u8 *bm; + int bit; + s64 vcn, byte, size; + + ntfs_log_trace("Entering\n"); + + bm = ntfs_attr_readall(icx->ni, AT_BITMAP, icx->name, icx->name_len, + &size); + if (!bm) + return (VCN)-1; + + for (byte = 0; byte < size; byte++) { + + if (bm[byte] == 255) + continue; + + for (bit = 0; bit < 8; bit++) { + if (!(bm[byte] & (1 << bit))) { + vcn = ntfs_ibm_pos_to_vcn(icx, byte * 8 + bit); + goto out; + } + } + } + + vcn = ntfs_ibm_pos_to_vcn(icx, size * 8); +out: + ntfs_log_trace("allocated vcn: %lld\n", (long long)vcn); + + if (ntfs_ibm_set(icx, vcn)) + vcn = (VCN)-1; + + free(bm); + return vcn; +} + +static INDEX_BLOCK *ntfs_ir_to_ib(INDEX_ROOT *ir, VCN ib_vcn) +{ + INDEX_BLOCK *ib; + INDEX_ENTRY *ie_last; + char *ies_start, *ies_end; + int i; + + ntfs_log_trace("Entering\n"); + + ib = ntfs_ib_alloc(ib_vcn, le32_to_cpu(ir->index_block_size), LEAF_NODE); + if (!ib) + return NULL; + + ies_start = (char *)ntfs_ie_get_first(&ir->index); + ies_end = (char *)ntfs_ie_get_end(&ir->index); + ie_last = ntfs_ie_get_last((INDEX_ENTRY *)ies_start, ies_end); + /* + * Copy all entries, including the termination entry + * as well, which can never have any data. + */ + i = (char *)ie_last - ies_start + le16_to_cpu(ie_last->length); + memcpy(ntfs_ie_get_first(&ib->index), ies_start, i); + + ib->index.ih_flags = ir->index.ih_flags; + ib->index.index_length = cpu_to_le32(i + + le32_to_cpu(ib->index.entries_offset)); + return ib; +} + +static void ntfs_ir_nill(INDEX_ROOT *ir) +{ + INDEX_ENTRY *ie_last; + char *ies_start, *ies_end; + + ntfs_log_trace("Entering\n"); + /* + * TODO: This function could be much simpler. + */ + ies_start = (char *)ntfs_ie_get_first(&ir->index); + ies_end = (char *)ntfs_ie_get_end(&ir->index); + ie_last = ntfs_ie_get_last((INDEX_ENTRY *)ies_start, ies_end); + /* + * Move the index root termination entry forward + */ + if ((char *)ie_last > ies_start) { + memmove(ies_start, (char *)ie_last, le16_to_cpu(ie_last->length)); + ie_last = (INDEX_ENTRY *)ies_start; + } +} + +static int ntfs_ib_copy_tail(ntfs_index_context *icx, INDEX_BLOCK *src, + INDEX_ENTRY *median, VCN new_vcn) +{ + u8 *ies_end; + INDEX_ENTRY *ie_head; /* first entry after the median */ + int tail_size, ret; + INDEX_BLOCK *dst; + + ntfs_log_trace("Entering\n"); + + dst = ntfs_ib_alloc(new_vcn, icx->block_size, + src->index.ih_flags & NODE_MASK); + if (!dst) + return STATUS_ERROR; + + ie_head = ntfs_ie_get_next(median); + + ies_end = (u8 *)ntfs_ie_get_end(&src->index); + tail_size = ies_end - (u8 *)ie_head; + memcpy(ntfs_ie_get_first(&dst->index), ie_head, tail_size); + + dst->index.index_length = cpu_to_le32(tail_size + + le32_to_cpu(dst->index.entries_offset)); + ret = ntfs_ib_write(icx, dst); + + free(dst); + return ret; +} + +static int ntfs_ib_cut_tail(ntfs_index_context *icx, INDEX_BLOCK *ib, + INDEX_ENTRY *ie) +{ + char *ies_start, *ies_end; + INDEX_ENTRY *ie_last; + + ntfs_log_trace("Entering\n"); + + ies_start = (char *)ntfs_ie_get_first(&ib->index); + ies_end = (char *)ntfs_ie_get_end(&ib->index); + + ie_last = ntfs_ie_get_last((INDEX_ENTRY *)ies_start, ies_end); + if (ie_last->ie_flags & INDEX_ENTRY_NODE) + ntfs_ie_set_vcn(ie_last, ntfs_ie_get_vcn(ie)); + + memcpy(ie, ie_last, le16_to_cpu(ie_last->length)); + + ib->index.index_length = cpu_to_le32(((char *)ie - ies_start) + + le16_to_cpu(ie->length) + le32_to_cpu(ib->index.entries_offset)); + + if (ntfs_ib_write(icx, ib)) + return STATUS_ERROR; + + return STATUS_OK; +} + +static int ntfs_ia_add(ntfs_index_context *icx) +{ + ntfs_log_trace("Entering\n"); + + if (ntfs_ibm_add(icx)) + return -1; + + if (!ntfs_attr_exist(icx->ni, AT_INDEX_ALLOCATION, icx->name, icx->name_len)) { + + if (ntfs_attr_add(icx->ni, AT_INDEX_ALLOCATION, icx->name, + icx->name_len, NULL, 0)) { + ntfs_log_perror("Failed to add AT_INDEX_ALLOCATION"); + return -1; + } + } + + icx->ia_na = ntfs_ia_open(icx, icx->ni); + if (!icx->ia_na) + return -1; + + return 0; +} + +static int ntfs_ir_reparent(ntfs_index_context *icx) +{ + ntfs_attr_search_ctx *ctx = NULL; + INDEX_ROOT *ir; + INDEX_ENTRY *ie; + INDEX_BLOCK *ib = NULL; + VCN new_ib_vcn; + int ret = STATUS_ERROR; + + ntfs_log_trace("Entering\n"); + + ir = ntfs_ir_lookup2(icx->ni, icx->name, icx->name_len); + if (!ir) + goto out; + + if ((ir->index.ih_flags & NODE_MASK) == SMALL_INDEX) + if (ntfs_ia_add(icx)) + goto out; + + new_ib_vcn = ntfs_ibm_get_free(icx); + if (new_ib_vcn == -1) + goto out; + + ir = ntfs_ir_lookup2(icx->ni, icx->name, icx->name_len); + if (!ir) + goto clear_bmp; + + ib = ntfs_ir_to_ib(ir, new_ib_vcn); + if (ib == NULL) { + ntfs_log_perror("Failed to move index root to index block"); + goto clear_bmp; + } + + if (ntfs_ib_write(icx, ib)) + goto clear_bmp; + + ir = ntfs_ir_lookup(icx->ni, icx->name, icx->name_len, &ctx); + if (!ir) + goto clear_bmp; + + ntfs_ir_nill(ir); + + ie = ntfs_ie_get_first(&ir->index); + ie->ie_flags |= INDEX_ENTRY_NODE; + ie->length = cpu_to_le16(sizeof(INDEX_ENTRY_HEADER) + sizeof(VCN)); + + ir->index.ih_flags = LARGE_INDEX; + ir->index.index_length = cpu_to_le32(le32_to_cpu(ir->index.entries_offset) + + le16_to_cpu(ie->length)); + ir->index.allocated_size = ir->index.index_length; + + if (ntfs_resident_attr_value_resize(ctx->mrec, ctx->attr, + sizeof(INDEX_ROOT) - sizeof(INDEX_HEADER) + + le32_to_cpu(ir->index.allocated_size))) + /* FIXME: revert index root */ + goto clear_bmp; + /* + * FIXME: do it earlier if we have enough space in IR (should always), + * so in error case we wouldn't lose the IB. + */ + ntfs_ie_set_vcn(ie, new_ib_vcn); + + ret = STATUS_OK; +err_out: + free(ib); + ntfs_attr_put_search_ctx(ctx); +out: + return ret; +clear_bmp: + ntfs_ibm_clear(icx, new_ib_vcn); + goto err_out; +} + +/** + * ntfs_ir_truncate - Truncate index root attribute + * + * Returns STATUS_OK, STATUS_RESIDENT_ATTRIBUTE_FILLED_MFT or STATUS_ERROR. + */ +static int ntfs_ir_truncate(ntfs_index_context *icx, int data_size) +{ + ntfs_attr *na; + int ret; + + ntfs_log_trace("Entering\n"); + + na = ntfs_attr_open(icx->ni, AT_INDEX_ROOT, icx->name, icx->name_len); + if (!na) { + ntfs_log_perror("Failed to open INDEX_ROOT"); + return STATUS_ERROR; + } + /* + * INDEX_ROOT must be resident and its entries can be moved to + * INDEX_BLOCK, so ENOSPC isn't a real error. + */ + ret = ntfs_attr_truncate(na, data_size + offsetof(INDEX_ROOT, index)); + if (ret == STATUS_OK) { + + icx->ir = ntfs_ir_lookup2(icx->ni, icx->name, icx->name_len); + if (!icx->ir) + return STATUS_ERROR; + + icx->ir->index.allocated_size = cpu_to_le32(data_size); + + } else if (ret == STATUS_ERROR) + ntfs_log_perror("Failed to truncate INDEX_ROOT"); + + ntfs_attr_close(na); + return ret; +} + +/** + * ntfs_ir_make_space - Make more space for the index root attribute + * + * On success return STATUS_OK or STATUS_KEEP_SEARCHING. + * On error return STATUS_ERROR. + */ +static int ntfs_ir_make_space(ntfs_index_context *icx, int data_size) +{ + int ret; + + ntfs_log_trace("Entering\n"); + + ret = ntfs_ir_truncate(icx, data_size); + if (ret == STATUS_RESIDENT_ATTRIBUTE_FILLED_MFT) { + + ret = ntfs_ir_reparent(icx); + if (ret == STATUS_OK) + ret = STATUS_KEEP_SEARCHING; + else + ntfs_log_perror("Failed to nodify INDEX_ROOT"); + } + + return ret; +} + +/* + * NOTE: 'ie' must be a copy of a real index entry. + */ +static int ntfs_ie_add_vcn(INDEX_ENTRY **ie) +{ + INDEX_ENTRY *p, *old = *ie; + + old->length = cpu_to_le16(le16_to_cpu(old->length) + sizeof(VCN)); + p = realloc(old, le16_to_cpu(old->length)); + if (!p) + return STATUS_ERROR; + + p->ie_flags |= INDEX_ENTRY_NODE; + *ie = p; + + return STATUS_OK; +} + +static int ntfs_ih_insert(INDEX_HEADER *ih, INDEX_ENTRY *orig_ie, VCN new_vcn, + int pos) +{ + INDEX_ENTRY *ie_node, *ie; + int ret = STATUS_ERROR; + VCN old_vcn; + + ntfs_log_trace("Entering\n"); + + ie = ntfs_ie_dup(orig_ie); + if (!ie) + return STATUS_ERROR; + + if (!(ie->ie_flags & INDEX_ENTRY_NODE)) + if (ntfs_ie_add_vcn(&ie)) + goto out; + + ie_node = ntfs_ie_get_by_pos(ih, pos); + old_vcn = ntfs_ie_get_vcn(ie_node); + ntfs_ie_set_vcn(ie_node, new_vcn); + + ntfs_ie_insert(ih, ie, ie_node); + ntfs_ie_set_vcn(ie_node, old_vcn); + ret = STATUS_OK; +out: + free(ie); + + return ret; +} + +static VCN ntfs_icx_parent_vcn(ntfs_index_context *icx) +{ + return icx->parent_vcn[icx->pindex]; +} + +static VCN ntfs_icx_parent_pos(ntfs_index_context *icx) +{ + return icx->parent_pos[icx->pindex]; +} + + +static int ntfs_ir_insert_median(ntfs_index_context *icx, INDEX_ENTRY *median, + VCN new_vcn) +{ + u32 new_size; + int ret; + + ntfs_log_trace("Entering\n"); + + icx->ir = ntfs_ir_lookup2(icx->ni, icx->name, icx->name_len); + if (!icx->ir) + return STATUS_ERROR; + + new_size = le32_to_cpu(icx->ir->index.index_length) + + le16_to_cpu(median->length); + if (!(median->ie_flags & INDEX_ENTRY_NODE)) + new_size += sizeof(VCN); + + ret = ntfs_ir_make_space(icx, new_size); + if (ret != STATUS_OK) + return ret; + + icx->ir = ntfs_ir_lookup2(icx->ni, icx->name, icx->name_len); + if (!icx->ir) + return STATUS_ERROR; + + return ntfs_ih_insert(&icx->ir->index, median, new_vcn, + ntfs_icx_parent_pos(icx)); +} + +static int ntfs_ib_split(ntfs_index_context *icx, INDEX_BLOCK *ib); + +/** + * On success return STATUS_OK or STATUS_KEEP_SEARCHING. + * On error return STATUS_ERROR. + */ +static int ntfs_ib_insert(ntfs_index_context *icx, INDEX_ENTRY *ie, VCN new_vcn) +{ + INDEX_BLOCK *ib; + u32 idx_size, allocated_size; + int err = STATUS_ERROR; + VCN old_vcn; + + ntfs_log_trace("Entering\n"); + + ib = ntfs_malloc(icx->block_size); + if (!ib) + return -1; + + old_vcn = ntfs_icx_parent_vcn(icx); + + if (ntfs_ib_read(icx, old_vcn, ib)) + goto err_out; + + idx_size = le32_to_cpu(ib->index.index_length); + allocated_size = le32_to_cpu(ib->index.allocated_size); + /* FIXME: sizeof(VCN) should be included only if ie has no VCN */ + if (idx_size + le16_to_cpu(ie->length) + sizeof(VCN) > allocated_size) { + err = ntfs_ib_split(icx, ib); + if (err == STATUS_OK) + err = STATUS_KEEP_SEARCHING; + goto err_out; + } + + if (ntfs_ih_insert(&ib->index, ie, new_vcn, ntfs_icx_parent_pos(icx))) + goto err_out; + + if (ntfs_ib_write(icx, ib)) + goto err_out; + + err = STATUS_OK; +err_out: + free(ib); + return err; +} + +/** + * ntfs_ib_split - Split an index block + * + * On success return STATUS_OK or STATUS_KEEP_SEARCHING. + * On error return is STATUS_ERROR. + */ +static int ntfs_ib_split(ntfs_index_context *icx, INDEX_BLOCK *ib) +{ + INDEX_ENTRY *median; + VCN new_vcn; + int ret; + + ntfs_log_trace("Entering\n"); + + if (ntfs_icx_parent_dec(icx)) + return STATUS_ERROR; + + median = ntfs_ie_get_median(&ib->index); + new_vcn = ntfs_ibm_get_free(icx); + if (new_vcn == -1) + return STATUS_ERROR; + + if (ntfs_ib_copy_tail(icx, ib, median, new_vcn)) { + ntfs_ibm_clear(icx, new_vcn); + return STATUS_ERROR; + } + + if (ntfs_icx_parent_vcn(icx) == VCN_INDEX_ROOT_PARENT) + ret = ntfs_ir_insert_median(icx, median, new_vcn); + else + ret = ntfs_ib_insert(icx, median, new_vcn); + + if (ret != STATUS_OK) { + ntfs_ibm_clear(icx, new_vcn); + return ret; + } + + ret = ntfs_ib_cut_tail(icx, ib, median); + + return ret; +} + +/* JPA static */ +int ntfs_ie_add(ntfs_index_context *icx, INDEX_ENTRY *ie) +{ + INDEX_HEADER *ih; + int allocated_size, new_size; + int ret = STATUS_ERROR; + +#ifdef DEBUG +/* removed by JPA to make function usable for security indexes + char *fn; + fn = ntfs_ie_filename_get(ie); + ntfs_log_trace("file: '%s'\n", fn); + ntfs_attr_name_free(&fn); +*/ +#endif + + while (1) { + + if (!ntfs_index_lookup(&ie->key, le16_to_cpu(ie->key_length), icx)) { + errno = EEXIST; + ntfs_log_perror("Index already have such entry"); + goto err_out; + } + if (errno != ENOENT) { + ntfs_log_perror("Failed to find place for new entry"); + goto err_out; + } + + if (icx->is_in_root) + ih = &icx->ir->index; + else + ih = &icx->ib->index; + + allocated_size = le32_to_cpu(ih->allocated_size); + new_size = le32_to_cpu(ih->index_length) + le16_to_cpu(ie->length); + + if (new_size <= allocated_size) + break; + + ntfs_log_trace("index block sizes: allocated: %d needed: %d\n", + allocated_size, new_size); + + if (icx->is_in_root) { + if (ntfs_ir_make_space(icx, new_size) == STATUS_ERROR) + goto err_out; + } else { + if (ntfs_ib_split(icx, icx->ib) == STATUS_ERROR) + goto err_out; + } + + ntfs_inode_mark_dirty(icx->actx->ntfs_ino); + ntfs_index_ctx_reinit(icx); + } + + ntfs_ie_insert(ih, ie, icx->entry); + ntfs_index_entry_mark_dirty(icx); + + ret = STATUS_OK; +err_out: + ntfs_log_trace("%s\n", ret ? "Failed" : "Done"); + return ret; +} + +/** + * ntfs_index_add_filename - add filename to directory index + * @ni: ntfs inode describing directory to which index add filename + * @fn: FILE_NAME attribute to add + * @mref: reference of the inode which @fn describes + * + * Return 0 on success or -1 on error with errno set to the error code. + */ +int ntfs_index_add_filename(ntfs_inode *ni, FILE_NAME_ATTR *fn, MFT_REF mref) +{ + INDEX_ENTRY *ie; + ntfs_index_context *icx; + int fn_size, ie_size, err, ret = -1; + + ntfs_log_trace("Entering\n"); + + if (!ni || !fn) { + ntfs_log_error("Invalid arguments.\n"); + errno = EINVAL; + return -1; + } + + fn_size = (fn->file_name_length * sizeof(ntfschar)) + + sizeof(FILE_NAME_ATTR); + ie_size = (sizeof(INDEX_ENTRY_HEADER) + fn_size + 7) & ~7; + + ie = ntfs_calloc(ie_size); + if (!ie) + return -1; + + ie->indexed_file = cpu_to_le64(mref); + ie->length = cpu_to_le16(ie_size); + ie->key_length = cpu_to_le16(fn_size); + memcpy(&ie->key, fn, fn_size); + + icx = ntfs_index_ctx_get(ni, NTFS_INDEX_I30, 4); + if (!icx) + goto out; + + ret = ntfs_ie_add(icx, ie); + err = errno; + ntfs_index_ctx_put(icx); + errno = err; +out: + free(ie); + return ret; +} + +static int ntfs_ih_takeout(ntfs_index_context *icx, INDEX_HEADER *ih, + INDEX_ENTRY *ie, INDEX_BLOCK *ib) +{ + INDEX_ENTRY *ie_roam; + int ret = STATUS_ERROR; + + ntfs_log_trace("Entering\n"); + + ie_roam = ntfs_ie_dup_novcn(ie); + if (!ie_roam) + return STATUS_ERROR; + + ntfs_ie_delete(ih, ie); + + if (ntfs_icx_parent_vcn(icx) == VCN_INDEX_ROOT_PARENT) + ntfs_inode_mark_dirty(icx->actx->ntfs_ino); + else + if (ntfs_ib_write(icx, ib)) + goto out; + + ntfs_index_ctx_reinit(icx); + + ret = ntfs_ie_add(icx, ie_roam); +out: + free(ie_roam); + return ret; +} + +/** + * Used if an empty index block to be deleted has END entry as the parent + * in the INDEX_ROOT which is the only one there. + */ +static void ntfs_ir_leafify(ntfs_index_context *icx, INDEX_HEADER *ih) +{ + INDEX_ENTRY *ie; + + ntfs_log_trace("Entering\n"); + + ie = ntfs_ie_get_first(ih); + ie->ie_flags &= ~INDEX_ENTRY_NODE; + ie->length = cpu_to_le16(le16_to_cpu(ie->length) - sizeof(VCN)); + + ih->index_length = cpu_to_le32(le32_to_cpu(ih->index_length) - sizeof(VCN)); + ih->ih_flags &= ~LARGE_INDEX; + + /* Not fatal error */ + ntfs_ir_truncate(icx, le32_to_cpu(ih->index_length)); +} + +/** + * Used if an empty index block to be deleted has END entry as the parent + * in the INDEX_ROOT which is not the only one there. + */ +static int ntfs_ih_reparent_end(ntfs_index_context *icx, INDEX_HEADER *ih, + INDEX_BLOCK *ib) +{ + INDEX_ENTRY *ie, *ie_prev; + + ntfs_log_trace("Entering\n"); + + ie = ntfs_ie_get_by_pos(ih, ntfs_icx_parent_pos(icx)); + ie_prev = ntfs_ie_prev(ih, ie); + + ntfs_ie_set_vcn(ie, ntfs_ie_get_vcn(ie_prev)); + + return ntfs_ih_takeout(icx, ih, ie_prev, ib); +} + +static int ntfs_index_rm_leaf(ntfs_index_context *icx) +{ + INDEX_BLOCK *ib = NULL; + INDEX_HEADER *parent_ih; + INDEX_ENTRY *ie; + int ret = STATUS_ERROR; + + ntfs_log_trace("pindex: %d\n", icx->pindex); + + if (ntfs_icx_parent_dec(icx)) + return STATUS_ERROR; + + if (ntfs_ibm_clear(icx, icx->parent_vcn[icx->pindex + 1])) + return STATUS_ERROR; + + if (ntfs_icx_parent_vcn(icx) == VCN_INDEX_ROOT_PARENT) + parent_ih = &icx->ir->index; + else { + ib = ntfs_malloc(icx->block_size); + if (!ib) + return STATUS_ERROR; + + if (ntfs_ib_read(icx, ntfs_icx_parent_vcn(icx), ib)) + goto out; + + parent_ih = &ib->index; + } + + ie = ntfs_ie_get_by_pos(parent_ih, ntfs_icx_parent_pos(icx)); + if (!ntfs_ie_end(ie)) { + ret = ntfs_ih_takeout(icx, parent_ih, ie, ib); + goto out; + } + + if (ntfs_ih_zero_entry(parent_ih)) { + + if (ntfs_icx_parent_vcn(icx) == VCN_INDEX_ROOT_PARENT) { + ntfs_ir_leafify(icx, parent_ih); + goto ok; + } + + ret = ntfs_index_rm_leaf(icx); + goto out; + } + + if (ntfs_ih_reparent_end(icx, parent_ih, ib)) + goto out; +ok: + ret = STATUS_OK; +out: + free(ib); + return ret; +} + +static int ntfs_index_rm_node(ntfs_index_context *icx) +{ + int entry_pos, pindex; + VCN vcn; + INDEX_BLOCK *ib = NULL; + INDEX_ENTRY *ie_succ, *ie, *entry = icx->entry; + INDEX_HEADER *ih; + u32 new_size; + int delta, ret = STATUS_ERROR; + + ntfs_log_trace("Entering\n"); + + if (!icx->ia_na) { + icx->ia_na = ntfs_ia_open(icx, icx->ni); + if (!icx->ia_na) + return STATUS_ERROR; + } + + ib = ntfs_malloc(icx->block_size); + if (!ib) + return STATUS_ERROR; + + ie_succ = ntfs_ie_get_next(icx->entry); + entry_pos = icx->parent_pos[icx->pindex]++; + pindex = icx->pindex; +descend: + vcn = ntfs_ie_get_vcn(ie_succ); + if (ntfs_ib_read(icx, vcn, ib)) + goto out; + + ie_succ = ntfs_ie_get_first(&ib->index); + + if (ntfs_icx_parent_inc(icx)) + goto out; + + icx->parent_vcn[icx->pindex] = vcn; + icx->parent_pos[icx->pindex] = 0; + + if ((ib->index.ih_flags & NODE_MASK) == INDEX_NODE) + goto descend; + + if (ntfs_ih_zero_entry(&ib->index)) { + errno = EIO; + ntfs_log_perror("Empty index block"); + goto out; + } + + ie = ntfs_ie_dup(ie_succ); + if (!ie) + goto out; + + if (ntfs_ie_add_vcn(&ie)) + goto out2; + + ntfs_ie_set_vcn(ie, ntfs_ie_get_vcn(icx->entry)); + + if (icx->is_in_root) + ih = &icx->ir->index; + else + ih = &icx->ib->index; + + delta = le16_to_cpu(ie->length) - le16_to_cpu(icx->entry->length); + new_size = le32_to_cpu(ih->index_length) + delta; + if (delta > 0) { + if (icx->is_in_root) { + ret = ntfs_ir_make_space(icx, new_size); + if (ret != STATUS_OK) + goto out2; + + ih = &icx->ir->index; + entry = ntfs_ie_get_by_pos(ih, entry_pos); + + } else if (new_size > le32_to_cpu(ih->allocated_size)) { + icx->pindex = pindex; + ret = ntfs_ib_split(icx, icx->ib); + if (ret == STATUS_OK) + ret = STATUS_KEEP_SEARCHING; + goto out2; + } + } + + ntfs_ie_delete(ih, entry); + ntfs_ie_insert(ih, ie, entry); + + if (icx->is_in_root) { + if (ntfs_ir_truncate(icx, new_size)) + goto out2; + } else + if (ntfs_icx_ib_write(icx)) + goto out2; + + ntfs_ie_delete(&ib->index, ie_succ); + + if (ntfs_ih_zero_entry(&ib->index)) { + if (ntfs_index_rm_leaf(icx)) + goto out2; + } else + if (ntfs_ib_write(icx, ib)) + goto out2; + + ret = STATUS_OK; +out2: + free(ie); +out: + free(ib); + return ret; +} + +/** + * ntfs_index_rm - remove entry from the index + * @icx: index context describing entry to delete + * + * Delete entry described by @icx from the index. Index context is always + * reinitialized after use of this function, so it can be used for index + * lookup once again. + * + * Return 0 on success or -1 on error with errno set to the error code. + */ +/*static JPA*/ +int ntfs_index_rm(ntfs_index_context *icx) +{ + INDEX_HEADER *ih; + int err, ret = STATUS_OK; + + ntfs_log_trace("Entering\n"); + + if (!icx || (!icx->ib && !icx->ir) || ntfs_ie_end(icx->entry)) { + ntfs_log_error("Invalid arguments.\n"); + errno = EINVAL; + goto err_out; + } + if (icx->is_in_root) + ih = &icx->ir->index; + else + ih = &icx->ib->index; + + if (icx->entry->ie_flags & INDEX_ENTRY_NODE) { + + ret = ntfs_index_rm_node(icx); + + } else if (icx->is_in_root || !ntfs_ih_one_entry(ih)) { + + ntfs_ie_delete(ih, icx->entry); + + if (icx->is_in_root) { + err = ntfs_ir_truncate(icx, le32_to_cpu(ih->index_length)); + if (err != STATUS_OK) + goto err_out; + } else + if (ntfs_icx_ib_write(icx)) + goto err_out; + } else { + if (ntfs_index_rm_leaf(icx)) + goto err_out; + } +out: + return ret; +err_out: + ret = STATUS_ERROR; + goto out; +} + +int ntfs_index_remove(ntfs_inode *dir_ni, ntfs_inode *ni, + const void *key, const int keylen) +{ + int ret = STATUS_ERROR; + ntfs_index_context *icx; + + icx = ntfs_index_ctx_get(dir_ni, NTFS_INDEX_I30, 4); + if (!icx) + return -1; + + while (1) { + + if (ntfs_index_lookup(key, keylen, icx)) + goto err_out; + + if ((((FILE_NAME_ATTR *)icx->data)->file_attributes & + FILE_ATTR_REPARSE_POINT) + && !ntfs_possible_symlink(ni)) { + errno = EOPNOTSUPP; + goto err_out; + } + + ret = ntfs_index_rm(icx); + if (ret == STATUS_ERROR) + goto err_out; + else if (ret == STATUS_OK) + break; + + ntfs_inode_mark_dirty(icx->actx->ntfs_ino); + ntfs_index_ctx_reinit(icx); + } + + ntfs_inode_mark_dirty(icx->actx->ntfs_ino); +out: + ntfs_index_ctx_put(icx); + return ret; +err_out: + ret = STATUS_ERROR; + ntfs_log_perror("Delete failed"); + goto out; +} + +/** + * ntfs_index_root_get - read the index root of an attribute + * @ni: open ntfs inode in which the ntfs attribute resides + * @attr: attribute for which we want its index root + * + * This function will read the related index root an ntfs attribute. + * + * On success a buffer is allocated with the content of the index root + * and which needs to be freed when it's not needed anymore. + * + * On error NULL is returned with errno set to the error code. + */ +INDEX_ROOT *ntfs_index_root_get(ntfs_inode *ni, ATTR_RECORD *attr) +{ + ntfs_attr_search_ctx *ctx; + ntfschar *name; + INDEX_ROOT *root = NULL; + + name = (ntfschar *)((u8 *)attr + le16_to_cpu(attr->name_offset)); + + if (!ntfs_ir_lookup(ni, name, attr->name_length, &ctx)) + return NULL; + + root = ntfs_malloc(sizeof(INDEX_ROOT)); + if (!root) + goto out; + + *root = *((INDEX_ROOT *)((u8 *)ctx->attr + + le16_to_cpu(ctx->attr->value_offset))); +out: + ntfs_attr_put_search_ctx(ctx); + return root; +} + + +/* + * Walk down the index tree (leaf bound) + * until there are no subnode in the first index entry + * returns the entry at the bottom left in subnode + */ + +static INDEX_ENTRY *ntfs_index_walk_down(INDEX_ENTRY *ie, + ntfs_index_context *ictx) +{ + INDEX_ENTRY *entry; + s64 vcn; + + entry = ie; + do { + vcn = ntfs_ie_get_vcn(entry); + if (ictx->is_in_root) { + + /* down from level zero */ + + ictx->ir = (INDEX_ROOT*)NULL; + ictx->ib = (INDEX_BLOCK*)ntfs_malloc(ictx->block_size); + ictx->pindex = 1; + ictx->is_in_root = FALSE; + } else { + + /* down from non-zero level */ + + ictx->pindex++; + } + ictx->parent_pos[ictx->pindex] = 0; + ictx->parent_vcn[ictx->pindex] = vcn; + if (!ntfs_ib_read(ictx,vcn,ictx->ib)) { + ictx->entry = ntfs_ie_get_first(&ictx->ib->index); + entry = ictx->entry; + } else + entry = (INDEX_ENTRY*)NULL; + } while (entry && (entry->ie_flags & INDEX_ENTRY_NODE)); + return (entry); +} + +/* + * Walk up the index tree (root bound) + * until there is a valid data entry in parent + * returns the parent entry or NULL if no more parent + */ + +static INDEX_ENTRY *ntfs_index_walk_up(INDEX_ENTRY *ie, + ntfs_index_context *ictx) +{ + INDEX_ENTRY *entry; + s64 vcn; + + entry = ie; + if (ictx->pindex > 0) { + do { + ictx->pindex--; + if (!ictx->pindex) { + + /* we have reached the root */ + + free(ictx->ib); + ictx->ib = (INDEX_BLOCK*)NULL; + ictx->is_in_root = TRUE; + /* a new search context is to be allocated */ + if (ictx->actx) + free(ictx->actx); + ictx->ir = ntfs_ir_lookup(ictx->ni, + ictx->name, ictx->name_len, + &ictx->actx); + if (ictx->ir) + entry = ntfs_ie_get_by_pos( + &ictx->ir->index, + ictx->parent_pos[ictx->pindex]); + else + entry = (INDEX_ENTRY*)NULL; + } else { + /* up into non-root node */ + vcn = ictx->parent_vcn[ictx->pindex]; + if (!ntfs_ib_read(ictx,vcn,ictx->ib)) { + entry = ntfs_ie_get_by_pos( + &ictx->ib->index, + ictx->parent_pos[ictx->pindex]); + } else + entry = (INDEX_ENTRY*)NULL; + } + ictx->entry = entry; + } while (entry && (ictx->pindex > 0) + && (entry->ie_flags & INDEX_ENTRY_END)); + } else + entry = (INDEX_ENTRY*)NULL; + return (entry); +} + +/* + * Get next entry in an index according to collating sequence. + * Must be initialized through a ntfs_index_lookup() + * + * Returns next entry or NULL if none + * + * Sample layout : + * + * +---+---+---+---+---+---+---+---+ n ptrs to subnodes + * | | | 10| 25| 33| | | | n-1 keys in between + * +---+---+---+---+---+---+---+---+ no key in last entry + * | A | A + * | | | +-------------------------------+ + * +--------------------------+ | +-----+ | + * | +--+ | | + * V | V | + * +---+---+---+---+---+---+---+---+ | +---+---+---+---+---+---+---+---+ + * | 11| 12| 13| 14| 15| 16| 17| | | | 26| 27| 28| 29| 30| 31| 32| | + * +---+---+---+---+---+---+---+---+ | +---+---+---+---+---+---+---+---+ + * | | + * +-----------------------+ | + * | | + * +---+---+---+---+---+---+---+---+ + * | 18| 19| 20| 21| 22| 23| 24| | + * +---+---+---+---+---+---+---+---+ + */ + +INDEX_ENTRY *ntfs_index_next(INDEX_ENTRY *ie, ntfs_index_context *ictx) +{ + INDEX_ENTRY *next; + int flags; + + /* + * lookup() may have returned an invalid node + * when searching for a partial key + * if this happens, walk up + */ + + if (ie->ie_flags & INDEX_ENTRY_END) + next = ntfs_index_walk_up(ie, ictx); + else { + /* + * get next entry in same node + * there is always one after any entry with data + */ + + next = (INDEX_ENTRY*)((char*)ie + le16_to_cpu(ie->length)); + ++ictx->parent_pos[ictx->pindex]; + flags = next->ie_flags; + + /* walk down if it has a subnode */ + + if (flags & INDEX_ENTRY_NODE) { + next = ntfs_index_walk_down(next,ictx); + } else { + + /* walk up it has no subnode, nor data */ + + if (flags & INDEX_ENTRY_END) { + next = ntfs_index_walk_up(next, ictx); + } + } + } + /* return NULL if stuck at end of a block */ + + if (next && (next->ie_flags & INDEX_ENTRY_END)) + next = (INDEX_ENTRY*)NULL; + return (next); +} + + diff --git a/libntfs-3g/inode.c b/libntfs-3g/inode.c new file mode 100755 index 0000000..6f3fa06 --- a/dev/null +++ b/libntfs-3g/inode.c @@ -0,0 +1,1566 @@ +/** + * inode.c - Inode handling code. Originated from the Linux-NTFS project. + * + * Copyright (c) 2002-2005 Anton Altaparmakov + * Copyright (c) 2002-2008 Szabolcs Szakacsits + * Copyright (c) 2004-2007 Yura Pakhuchiy + * Copyright (c) 2004-2005 Richard Russon + * Copyright (c) 2009-2010 Jean-Pierre Andre + * + * This program/include file 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/include file 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 (in the main directory of the NTFS-3G + * distribution in the file COPYING); if not, write to the Free Software + * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_ERRNO_H +#include +#endif +#ifdef HAVE_SETXATTR +#include +#endif + +#include "param.h" +#include "compat.h" +#include "types.h" +#include "volume.h" +#include "cache.h" +#include "inode.h" +#include "attrib.h" +#include "debug.h" +#include "mft.h" +#include "attrlist.h" +#include "runlist.h" +#include "lcnalloc.h" +#include "index.h" +#include "dir.h" +#include "ntfstime.h" +#include "logging.h" +#include "misc.h" + +ntfs_inode *ntfs_inode_base(ntfs_inode *ni) +{ + if (ni->nr_extents == -1) + return ni->base_ni; + return ni; +} + +/** + * ntfs_inode_mark_dirty - set the inode (and its base inode if it exists) dirty + * @ni: ntfs inode to set dirty + * + * Set the inode @ni dirty so it is written out later (at the latest at + * ntfs_inode_close() time). If @ni is an extent inode, set the base inode + * dirty, too. + * + * This function cannot fail. + */ +void ntfs_inode_mark_dirty(ntfs_inode *ni) +{ + NInoSetDirty(ni); + if (ni->nr_extents == -1) + NInoSetDirty(ni->base_ni); +} + +/** + * __ntfs_inode_allocate - Create and initialise an NTFS inode object + * @vol: + * + * Description... + * + * Returns: + */ +static ntfs_inode *__ntfs_inode_allocate(ntfs_volume *vol) +{ + ntfs_inode *ni; + + ni = (ntfs_inode*)ntfs_calloc(sizeof(ntfs_inode)); + if (ni) + ni->vol = vol; + return ni; +} + +/** + * ntfs_inode_allocate - Create an NTFS inode object + * @vol: + * + * Description... + * + * Returns: + */ +ntfs_inode *ntfs_inode_allocate(ntfs_volume *vol) +{ + return __ntfs_inode_allocate(vol); +} + +/** + * __ntfs_inode_release - Destroy an NTFS inode object + * @ni: + * + * Description... + * + * Returns: + */ +static void __ntfs_inode_release(ntfs_inode *ni) +{ + if (NInoDirty(ni)) + ntfs_log_error("Releasing dirty inode %lld!\n", + (long long)ni->mft_no); + if (NInoAttrList(ni) && ni->attr_list) + free(ni->attr_list); + free(ni->mrec); + free(ni); + return; +} + +/** + * ntfs_inode_open - open an inode ready for access + * @vol: volume to get the inode from + * @mref: inode number / mft record number to open + * + * Allocate an ntfs_inode structure and initialize it for the given inode + * specified by @mref. @mref specifies the inode number / mft record to read, + * including the sequence number, which can be 0 if no sequence number checking + * is to be performed. + * + * Then, allocate a buffer for the mft record, read the mft record from the + * volume @vol, and attach it to the ntfs_inode structure (->mrec). The + * mft record is mst deprotected and sanity checked for validity and we abort + * if deprotection or checks fail. + * + * Finally, search for an attribute list attribute in the mft record and if one + * is found, load the attribute list attribute value and attach it to the + * ntfs_inode structure (->attr_list). Also set the NI_AttrList bit to indicate + * this. + * + * Return a pointer to the ntfs_inode structure on success or NULL on error, + * with errno set to the error code. + */ +static ntfs_inode *ntfs_inode_real_open(ntfs_volume *vol, const MFT_REF mref) +{ + s64 l; + ntfs_inode *ni = NULL; + ntfs_attr_search_ctx *ctx; + STANDARD_INFORMATION *std_info; + le32 lthle; + int olderrno; + + ntfs_log_enter("Entering for inode %lld\n", (long long)MREF(mref)); + if (!vol) { + errno = EINVAL; + goto out; + } + ni = __ntfs_inode_allocate(vol); + if (!ni) + goto out; + if (ntfs_file_record_read(vol, mref, &ni->mrec, NULL)) + goto err_out; + if (!(ni->mrec->flags & MFT_RECORD_IN_USE)) { + errno = ENOENT; + goto err_out; + } + ni->mft_no = MREF(mref); + ctx = ntfs_attr_get_search_ctx(ni, NULL); + if (!ctx) + goto err_out; + /* Receive some basic information about inode. */ + if (ntfs_attr_lookup(AT_STANDARD_INFORMATION, AT_UNNAMED, + 0, CASE_SENSITIVE, 0, NULL, 0, ctx)) { + if (!ni->mrec->base_mft_record) + ntfs_log_perror("No STANDARD_INFORMATION in base record" + " %lld", (long long)MREF(mref)); + goto put_err_out; + } + std_info = (STANDARD_INFORMATION *)((u8 *)ctx->attr + + le16_to_cpu(ctx->attr->value_offset)); + ni->flags = std_info->file_attributes; + ni->creation_time = std_info->creation_time; + ni->last_data_change_time = std_info->last_data_change_time; + ni->last_mft_change_time = std_info->last_mft_change_time; + ni->last_access_time = std_info->last_access_time; + /* JPA insert v3 extensions if present */ + /* length may be seen as 72 (v1.x) or 96 (v3.x) */ + lthle = ctx->attr->length; + if (le32_to_cpu(lthle) > sizeof(STANDARD_INFORMATION)) { + set_nino_flag(ni, v3_Extensions); + ni->owner_id = std_info->owner_id; + ni->security_id = std_info->security_id; + ni->quota_charged = std_info->quota_charged; + ni->usn = std_info->usn; + } else { + clear_nino_flag(ni, v3_Extensions); + ni->owner_id = const_cpu_to_le32(0); + ni->security_id = const_cpu_to_le32(0); + } + /* Set attribute list information. */ + olderrno = errno; + if (ntfs_attr_lookup(AT_ATTRIBUTE_LIST, AT_UNNAMED, 0, + CASE_SENSITIVE, 0, NULL, 0, ctx)) { + if (errno != ENOENT) + goto put_err_out; + /* Attribute list attribute does not present. */ + /* restore previous errno to avoid misinterpretation */ + errno = olderrno; + goto get_size; + } + NInoSetAttrList(ni); + l = ntfs_get_attribute_value_length(ctx->attr); + if (!l) + goto put_err_out; + if (l > 0x40000) { + errno = EIO; + ntfs_log_perror("Too large attrlist attribute (%lld), inode " + "%lld", (long long)l, (long long)MREF(mref)); + goto put_err_out; + } + ni->attr_list_size = l; + ni->attr_list = ntfs_malloc(ni->attr_list_size); + if (!ni->attr_list) + goto put_err_out; + l = ntfs_get_attribute_value(vol, ctx->attr, ni->attr_list); + if (!l) + goto put_err_out; + if (l != ni->attr_list_size) { + errno = EIO; + ntfs_log_perror("Unexpected attrlist size (%lld <> %u), inode " + "%lld", (long long)l, ni->attr_list_size, + (long long)MREF(mref)); + goto put_err_out; + } +get_size: + olderrno = errno; + if (ntfs_attr_lookup(AT_DATA, AT_UNNAMED, 0, 0, 0, NULL, 0, ctx)) { + if (errno != ENOENT) + goto put_err_out; + /* Directory or special file. */ + /* restore previous errno to avoid misinterpretation */ + errno = olderrno; + ni->data_size = ni->allocated_size = 0; + } else { + if (ctx->attr->non_resident) { + ni->data_size = sle64_to_cpu(ctx->attr->data_size); + if (ctx->attr->flags & + (ATTR_IS_COMPRESSED | ATTR_IS_SPARSE)) + ni->allocated_size = sle64_to_cpu( + ctx->attr->compressed_size); + else + ni->allocated_size = sle64_to_cpu( + ctx->attr->allocated_size); + } else { + ni->data_size = le32_to_cpu(ctx->attr->value_length); + ni->allocated_size = (ni->data_size + 7) & ~7; + } + set_nino_flag(ni,KnownSize); + } + ntfs_attr_put_search_ctx(ctx); +out: + ntfs_log_leave("\n"); + return ni; + +put_err_out: + ntfs_attr_put_search_ctx(ctx); +err_out: + __ntfs_inode_release(ni); + ni = NULL; + goto out; +} + +/** + * ntfs_inode_close - close an ntfs inode and free all associated memory + * @ni: ntfs inode to close + * + * Make sure the ntfs inode @ni is clean. + * + * If the ntfs inode @ni is a base inode, close all associated extent inodes, + * then deallocate all memory attached to it, and finally free the ntfs inode + * structure itself. + * + * If it is an extent inode, we disconnect it from its base inode before we + * destroy it. + * + * It is OK to pass NULL to this function, it is just noop in this case. + * + * Return 0 on success or -1 on error with errno set to the error code. On + * error, @ni has not been freed. The user should attempt to handle the error + * and call ntfs_inode_close() again. The following error codes are defined: + * + * EBUSY @ni and/or its attribute list runlist is/are dirty and the + * attempt to write it/them to disk failed. + * EINVAL @ni is invalid (probably it is an extent inode). + * EIO I/O error while trying to write inode to disk. + */ + +int ntfs_inode_real_close(ntfs_inode *ni) +{ + int ret = -1; + + if (!ni) + return 0; + + ntfs_log_enter("Entering for inode %lld\n", (long long)ni->mft_no); + + /* If we have dirty metadata, write it out. */ + if (NInoDirty(ni) || NInoAttrListDirty(ni)) { + if (ntfs_inode_sync(ni)) { + if (errno != EIO) + errno = EBUSY; + goto err; + } + } + /* Is this a base inode with mapped extent inodes? */ + if (ni->nr_extents > 0) { + while (ni->nr_extents > 0) { + if (ntfs_inode_real_close(ni->extent_nis[0])) { + if (errno != EIO) + errno = EBUSY; + goto err; + } + } + } else if (ni->nr_extents == -1) { + ntfs_inode **tmp_nis; + ntfs_inode *base_ni; + s32 i; + + /* + * If the inode is an extent inode, disconnect it from the + * base inode before destroying it. + */ + base_ni = ni->base_ni; + for (i = 0; i < base_ni->nr_extents; ++i) { + tmp_nis = base_ni->extent_nis; + if (tmp_nis[i] != ni) + continue; + /* Found it. Disconnect. */ + memmove(tmp_nis + i, tmp_nis + i + 1, + (base_ni->nr_extents - i - 1) * + sizeof(ntfs_inode *)); + /* Buffer should be for multiple of four extents. */ + if ((--base_ni->nr_extents) & 3) { + i = -1; + break; + } + /* + * ElectricFence is unhappy with realloc(x,0) as free(x) + * thus we explicitly separate these two cases. + */ + if (base_ni->nr_extents) { + /* Resize the memory buffer. */ + tmp_nis = realloc(tmp_nis, base_ni->nr_extents * + sizeof(ntfs_inode *)); + /* Ignore errors, they don't really matter. */ + if (tmp_nis) + base_ni->extent_nis = tmp_nis; + } else if (tmp_nis) { + free(tmp_nis); + base_ni->extent_nis = (ntfs_inode**)NULL; + } + /* Allow for error checking. */ + i = -1; + break; + } + + /* + * We could successfully sync, so only log this error + * and try to sync other inode extents too. + */ + if (i != -1) + ntfs_log_error("Extent inode %lld was not found\n", + (long long)ni->mft_no); + } + + __ntfs_inode_release(ni); + ret = 0; +err: + ntfs_log_leave("\n"); + return ret; +} + +#if CACHE_NIDATA_SIZE + +/* + * Free an inode structure when there is not more space + * in the cache + */ + +void ntfs_inode_nidata_free(const struct CACHED_GENERIC *cached) +{ + ntfs_inode_real_close(((const struct CACHED_NIDATA*)cached)->ni); +} + +/* + * Compute a hash value for an inode entry + */ + +int ntfs_inode_nidata_hash(const struct CACHED_GENERIC *item) +{ + return (((const struct CACHED_NIDATA*)item)->inum + % (2*CACHE_NIDATA_SIZE)); +} + +/* + * inum comparing for entering/fetching from cache + */ + +static int idata_cache_compare(const struct CACHED_GENERIC *cached, + const struct CACHED_GENERIC *wanted) +{ + return (((const struct CACHED_NIDATA*)cached)->inum + != ((const struct CACHED_NIDATA*)wanted)->inum); +} + +/* + * Invalidate an inode entry when not needed anymore. + * The entry should have been synced, it may be reused later, + * if it is requested before it is dropped from cache. + */ + +void ntfs_inode_invalidate(ntfs_volume *vol, const MFT_REF mref) +{ + struct CACHED_NIDATA item; + int count; + + item.inum = MREF(mref); + item.ni = (ntfs_inode*)NULL; + item.pathname = (const char*)NULL; + item.varsize = 0; + count = ntfs_invalidate_cache(vol->nidata_cache, + GENERIC(&item),idata_cache_compare,CACHE_FREE); +} + +#endif + +/* + * Open an inode + * + * When possible, an entry recorded in the cache is reused + * + * **NEVER REOPEN** an inode, this can lead to a duplicated + * cache entry (hard to detect), and to an obsolete one being + * reused. System files are however protected from being cached. + */ + +ntfs_inode *ntfs_inode_open(ntfs_volume *vol, const MFT_REF mref) +{ + ntfs_inode *ni; +#if CACHE_NIDATA_SIZE + struct CACHED_NIDATA item; + struct CACHED_NIDATA *cached; + + /* fetch idata from cache */ + item.inum = MREF(mref); + debug_double_inode(item.inum,1); + item.pathname = (const char*)NULL; + item.varsize = 0; + cached = (struct CACHED_NIDATA*)ntfs_fetch_cache(vol->nidata_cache, + GENERIC(&item),idata_cache_compare); + if (cached) { + ni = cached->ni; + /* do not keep open entries in cache */ + ntfs_remove_cache(vol->nidata_cache, + (struct CACHED_GENERIC*)cached,0); + } else { + ni = ntfs_inode_real_open(vol, mref); + } +#else + ni = ntfs_inode_real_open(vol, mref); +#endif + return (ni); +} + +/* + * Close an inode entry + * + * If cacheing is in use, the entry is synced and kept available + * in cache for further use. + * + * System files (inode < 16 or having the IS_4 flag) are protected + * against being cached. + */ + +int ntfs_inode_close(ntfs_inode *ni) +{ + int res; +#if CACHE_NIDATA_SIZE + BOOL dirty; + struct CACHED_NIDATA item; + + if (ni) { + debug_double_inode(ni->mft_no,0); + /* do not cache system files : could lead to double entries */ + if (ni->vol && ni->vol->nidata_cache + && ((ni->mft_no == FILE_root) + || ((ni->mft_no >= FILE_first_user) + && !(ni->mrec->flags & MFT_RECORD_IS_4)))) { + /* If we have dirty metadata, write it out. */ + dirty = NInoDirty(ni) || NInoAttrListDirty(ni); + if (dirty) { + res = ntfs_inode_sync(ni); + /* do a real close if sync failed */ + if (res) + ntfs_inode_real_close(ni); + } else + res = 0; + + if (!res) { + /* feed idata into cache */ + item.inum = ni->mft_no; + item.ni = ni; + item.pathname = (const char*)NULL; + item.varsize = 0; + debug_cached_inode(ni); + ntfs_enter_cache(ni->vol->nidata_cache, + GENERIC(&item), idata_cache_compare); + } + } else { + /* cache not ready or system file, really close */ + res = ntfs_inode_real_close(ni); + } + } else + res = 0; +#else + res = ntfs_inode_real_close(ni); +#endif + return (res); +} + +/** + * ntfs_extent_inode_open - load an extent inode and attach it to its base + * @base_ni: base ntfs inode + * @mref: mft reference of the extent inode to load (in little endian) + * + * First check if the extent inode @mref is already attached to the base ntfs + * inode @base_ni, and if so, return a pointer to the attached extent inode. + * + * If the extent inode is not already attached to the base inode, allocate an + * ntfs_inode structure and initialize it for the given inode @mref. @mref + * specifies the inode number / mft record to read, including the sequence + * number, which can be 0 if no sequence number checking is to be performed. + * + * Then, allocate a buffer for the mft record, read the mft record from the + * volume @base_ni->vol, and attach it to the ntfs_inode structure (->mrec). + * The mft record is mst deprotected and sanity checked for validity and we + * abort if deprotection or checks fail. + * + * Finally attach the ntfs inode to its base inode @base_ni and return a + * pointer to the ntfs_inode structure on success or NULL on error, with errno + * set to the error code. + * + * Note, extent inodes are never closed directly. They are automatically + * disposed off by the closing of the base inode. + */ +ntfs_inode *ntfs_extent_inode_open(ntfs_inode *base_ni, const MFT_REF mref) +{ + u64 mft_no = MREF_LE(mref); + ntfs_inode *ni = NULL; + ntfs_inode **extent_nis; + int i; + + if (!base_ni) { + errno = EINVAL; + ntfs_log_perror("%s", __FUNCTION__); + return NULL; + } + + ntfs_log_enter("Opening extent inode %lld (base mft record %lld).\n", + (unsigned long long)mft_no, + (unsigned long long)base_ni->mft_no); + + /* Is the extent inode already open and attached to the base inode? */ + if (base_ni->nr_extents > 0) { + extent_nis = base_ni->extent_nis; + for (i = 0; i < base_ni->nr_extents; i++) { + u16 seq_no; + + ni = extent_nis[i]; + if (mft_no != ni->mft_no) + continue; + /* Verify the sequence number if given. */ + seq_no = MSEQNO_LE(mref); + if (seq_no && seq_no != le16_to_cpu( + ni->mrec->sequence_number)) { + errno = EIO; + ntfs_log_perror("Found stale extent mft " + "reference mft=%lld", + (long long)ni->mft_no); + goto out; + } + goto out; + } + } + /* Wasn't there, we need to load the extent inode. */ + ni = __ntfs_inode_allocate(base_ni->vol); + if (!ni) + goto out; + if (ntfs_file_record_read(base_ni->vol, le64_to_cpu(mref), &ni->mrec, NULL)) + goto err_out; + ni->mft_no = mft_no; + ni->nr_extents = -1; + ni->base_ni = base_ni; + /* Attach extent inode to base inode, reallocating memory if needed. */ + if (!(base_ni->nr_extents & 3)) { + i = (base_ni->nr_extents + 4) * sizeof(ntfs_inode *); + + extent_nis = ntfs_malloc(i); + if (!extent_nis) + goto err_out; + if (base_ni->nr_extents) { + memcpy(extent_nis, base_ni->extent_nis, + i - 4 * sizeof(ntfs_inode *)); + free(base_ni->extent_nis); + } + base_ni->extent_nis = extent_nis; + } + base_ni->extent_nis[base_ni->nr_extents++] = ni; +out: + ntfs_log_leave("\n"); + return ni; +err_out: + __ntfs_inode_release(ni); + ni = NULL; + goto out; +} + +/** + * ntfs_inode_attach_all_extents - attach all extents for target inode + * @ni: opened ntfs inode for which perform attach + * + * Return 0 on success and -1 on error with errno set to the error code. + */ +int ntfs_inode_attach_all_extents(ntfs_inode *ni) +{ + ATTR_LIST_ENTRY *ale; + u64 prev_attached = 0; + + if (!ni) { + ntfs_log_trace("Invalid arguments.\n"); + errno = EINVAL; + return -1; + } + + if (ni->nr_extents == -1) + ni = ni->base_ni; + + ntfs_log_trace("Entering for inode 0x%llx.\n", (long long) ni->mft_no); + + /* Inode haven't got attribute list, thus nothing to attach. */ + if (!NInoAttrList(ni)) + return 0; + + if (!ni->attr_list) { + ntfs_log_trace("Corrupt in-memory struct.\n"); + errno = EINVAL; + return -1; + } + + /* Walk through attribute list and attach all extents. */ + errno = 0; + ale = (ATTR_LIST_ENTRY *)ni->attr_list; + while ((u8*)ale < ni->attr_list + ni->attr_list_size) { + if (ni->mft_no != MREF_LE(ale->mft_reference) && + prev_attached != MREF_LE(ale->mft_reference)) { + if (!ntfs_extent_inode_open(ni, ale->mft_reference)) { + ntfs_log_trace("Couldn't attach extent inode.\n"); + return -1; + } + prev_attached = MREF_LE(ale->mft_reference); + } + ale = (ATTR_LIST_ENTRY *)((u8*)ale + le16_to_cpu(ale->length)); + } + return 0; +} + +/** + * ntfs_inode_sync_standard_information - update standard information attribute + * @ni: ntfs inode to update standard information + * + * Return 0 on success or -1 on error with errno set to the error code. + */ +static int ntfs_inode_sync_standard_information(ntfs_inode *ni) +{ + ntfs_attr_search_ctx *ctx; + STANDARD_INFORMATION *std_info; + u32 lth; + le32 lthle; + + ntfs_log_trace("Entering for inode %lld\n", (long long)ni->mft_no); + + ctx = ntfs_attr_get_search_ctx(ni, NULL); + if (!ctx) + return -1; + if (ntfs_attr_lookup(AT_STANDARD_INFORMATION, AT_UNNAMED, + 0, CASE_SENSITIVE, 0, NULL, 0, ctx)) { + ntfs_log_perror("Failed to sync standard info (inode %lld)", + (long long)ni->mft_no); + ntfs_attr_put_search_ctx(ctx); + return -1; + } + std_info = (STANDARD_INFORMATION *)((u8 *)ctx->attr + + le16_to_cpu(ctx->attr->value_offset)); + std_info->file_attributes = ni->flags; + if (!test_nino_flag(ni, TimesSet)) { + std_info->creation_time = ni->creation_time; + std_info->last_data_change_time = ni->last_data_change_time; + std_info->last_mft_change_time = ni->last_mft_change_time; + std_info->last_access_time = ni->last_access_time; + } + + /* JPA update v3.x extensions, ensuring consistency */ + + lthle = ctx->attr->length; + lth = le32_to_cpu(lthle); + if (test_nino_flag(ni, v3_Extensions) + && (lth <= sizeof(STANDARD_INFORMATION))) + ntfs_log_error("bad sync of standard information\n"); + + if (lth > sizeof(STANDARD_INFORMATION)) { + std_info->owner_id = ni->owner_id; + std_info->security_id = ni->security_id; + std_info->quota_charged = ni->quota_charged; + std_info->usn = ni->usn; + } + ntfs_inode_mark_dirty(ctx->ntfs_ino); + ntfs_attr_put_search_ctx(ctx); + return 0; +} + +/** + * ntfs_inode_sync_file_name - update FILE_NAME attributes + * @ni: ntfs inode to update FILE_NAME attributes + * + * Update all FILE_NAME attributes for inode @ni in the index. + * + * Return 0 on success or -1 on error with errno set to the error code. + */ +static int ntfs_inode_sync_file_name(ntfs_inode *ni, ntfs_inode *dir_ni) +{ + ntfs_attr_search_ctx *ctx = NULL; + ntfs_index_context *ictx; + ntfs_inode *index_ni; + FILE_NAME_ATTR *fn; + FILE_NAME_ATTR *fnx; + REPARSE_POINT *rpp; + le32 reparse_tag; + int err = 0; + + ntfs_log_trace("Entering for inode %lld\n", (long long)ni->mft_no); + + ctx = ntfs_attr_get_search_ctx(ni, NULL); + if (!ctx) { + err = errno; + goto err_out; + } + /* Collect the reparse tag, if any */ + reparse_tag = cpu_to_le32(0); + if (ni->flags & FILE_ATTR_REPARSE_POINT) { + if (!ntfs_attr_lookup(AT_REPARSE_POINT, NULL, + 0, CASE_SENSITIVE, 0, NULL, 0, ctx)) { + rpp = (REPARSE_POINT*)((u8 *)ctx->attr + + le16_to_cpu(ctx->attr->value_offset)); + reparse_tag = rpp->reparse_tag; + } + ntfs_attr_reinit_search_ctx(ctx); + } + /* Walk through all FILE_NAME attributes and update them. */ + while (!ntfs_attr_lookup(AT_FILE_NAME, NULL, 0, 0, 0, NULL, 0, ctx)) { + fn = (FILE_NAME_ATTR *)((u8 *)ctx->attr + + le16_to_cpu(ctx->attr->value_offset)); + if (MREF_LE(fn->parent_directory) == ni->mft_no) { + /* + * WARNING: We cheat here and obtain 2 attribute + * search contexts for one inode (first we obtained + * above, second will be obtained inside + * ntfs_index_lookup), it's acceptable for library, + * but will deadlock in the kernel. + */ + index_ni = ni; + } else + if (dir_ni) + index_ni = dir_ni; + else + index_ni = ntfs_inode_open(ni->vol, + le64_to_cpu(fn->parent_directory)); + if (!index_ni) { + if (!err) + err = errno; + ntfs_log_perror("Failed to open inode %lld with index", + (long long)le64_to_cpu(fn->parent_directory)); + continue; + } + ictx = ntfs_index_ctx_get(index_ni, NTFS_INDEX_I30, 4); + if (!ictx) { + if (!err) + err = errno; + ntfs_log_perror("Failed to get index ctx, inode %lld", + (long long)index_ni->mft_no); + if ((ni != index_ni) && !dir_ni + && ntfs_inode_close(index_ni) && !err) + err = errno; + continue; + } + if (ntfs_index_lookup(fn, sizeof(FILE_NAME_ATTR), ictx)) { + if (!err) { + if (errno == ENOENT) + err = EIO; + else + err = errno; + } + ntfs_log_perror("Index lookup failed, inode %lld", + (long long)index_ni->mft_no); + ntfs_index_ctx_put(ictx); + if (ni != index_ni && ntfs_inode_close(index_ni) && !err) + err = errno; + continue; + } + /* Update flags and file size. */ + fnx = (FILE_NAME_ATTR *)ictx->data; + fnx->file_attributes = + (fnx->file_attributes & ~FILE_ATTR_VALID_FLAGS) | + (ni->flags & FILE_ATTR_VALID_FLAGS); + if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) + fnx->data_size = fnx->allocated_size + = const_cpu_to_le64(0); + else { + fnx->allocated_size = cpu_to_sle64(ni->allocated_size); + fnx->data_size = cpu_to_sle64(ni->data_size); + } + /* update or clear the reparse tag in the index */ + fnx->reparse_point_tag = reparse_tag; + if (!test_nino_flag(ni, TimesSet)) { + fnx->creation_time = ni->creation_time; + fnx->last_data_change_time = ni->last_data_change_time; + fnx->last_mft_change_time = ni->last_mft_change_time; + fnx->last_access_time = ni->last_access_time; + } else { + fnx->creation_time = fn->creation_time; + fnx->last_data_change_time = fn->last_data_change_time; + fnx->last_mft_change_time = fn->last_mft_change_time; + fnx->last_access_time = fn->last_access_time; + } + ntfs_index_entry_mark_dirty(ictx); + ntfs_index_ctx_put(ictx); + if ((ni != index_ni) && !dir_ni + && ntfs_inode_close(index_ni) && !err) + err = errno; + } + /* Check for real error occurred. */ + if (errno != ENOENT) { + err = errno; + ntfs_log_perror("Attribute lookup failed, inode %lld", + (long long)ni->mft_no); + goto err_out; + } + ntfs_attr_put_search_ctx(ctx); + if (err) { + errno = err; + return -1; + } + return 0; +err_out: + if (ctx) + ntfs_attr_put_search_ctx(ctx); + errno = err; + return -1; +} + +/** + * ntfs_inode_sync - write the inode (and its dirty extents) to disk + * @ni: ntfs inode to write + * + * Write the inode @ni to disk as well as its dirty extent inodes if such + * exist and @ni is a base inode. If @ni is an extent inode, only @ni is + * written completely disregarding its base inode and any other extent inodes. + * + * For a base inode with dirty extent inodes if any writes fail for whatever + * reason, the failing inode is skipped and the sync process is continued. At + * the end the error condition that brought about the failure is returned. Thus + * the smallest amount of data loss possible occurs. + * + * Return 0 on success or -1 on error with errno set to the error code. + * The following error codes are defined: + * EINVAL - Invalid arguments were passed to the function. + * EBUSY - Inode and/or one of its extents is busy, try again later. + * EIO - I/O error while writing the inode (or one of its extents). + */ +static int ntfs_inode_sync_in_dir(ntfs_inode *ni, ntfs_inode *dir_ni) +{ + int ret = 0; + int err = 0; + if (!ni) { + errno = EINVAL; + ntfs_log_error("Failed to sync NULL inode\n"); + return -1; + } + + ntfs_log_enter("Entering for inode %lld\n", (long long)ni->mft_no); + + /* Update STANDARD_INFORMATION. */ + if ((ni->mrec->flags & MFT_RECORD_IN_USE) && ni->nr_extents != -1 && + ntfs_inode_sync_standard_information(ni)) { + if (!err || errno == EIO) { + err = errno; + if (err != EIO) + err = EBUSY; + } + } + + /* Update FILE_NAME's in the index. */ + if ((ni->mrec->flags & MFT_RECORD_IN_USE) && ni->nr_extents != -1 && + NInoFileNameTestAndClearDirty(ni) && + ntfs_inode_sync_file_name(ni, dir_ni)) { + if (!err || errno == EIO) { + err = errno; + if (err != EIO) + err = EBUSY; + } + ntfs_log_perror("Failed to sync FILE_NAME (inode %lld)", + (long long)ni->mft_no); + NInoFileNameSetDirty(ni); + } + + /* Write out attribute list from cache to disk. */ + if ((ni->mrec->flags & MFT_RECORD_IN_USE) && ni->nr_extents != -1 && + NInoAttrList(ni) && NInoAttrListTestAndClearDirty(ni)) { + ntfs_attr *na; + + na = ntfs_attr_open(ni, AT_ATTRIBUTE_LIST, AT_UNNAMED, 0); + if (!na) { + if (!err || errno == EIO) { + err = errno; + if (err != EIO) + err = EBUSY; + ntfs_log_perror("Attribute list sync failed " + "(open, inode %lld)", + (long long)ni->mft_no); + } + NInoAttrListSetDirty(ni); + goto sync_inode; + } + + if (na->data_size == ni->attr_list_size) { + if (ntfs_attr_pwrite(na, 0, ni->attr_list_size, + ni->attr_list) != ni->attr_list_size) { + if (!err || errno == EIO) { + err = errno; + if (err != EIO) + err = EBUSY; + ntfs_log_perror("Attribute list sync " + "failed (write, inode %lld)", + (long long)ni->mft_no); + } + NInoAttrListSetDirty(ni); + } + } else { + err = EIO; + ntfs_log_error("Attribute list sync failed (bad size, " + "inode %lld)\n", (long long)ni->mft_no); + NInoAttrListSetDirty(ni); + } + ntfs_attr_close(na); + } + +sync_inode: + /* Write this inode out to the $MFT (and $MFTMirr if applicable). */ + if (NInoTestAndClearDirty(ni)) { + if (ntfs_mft_record_write(ni->vol, ni->mft_no, ni->mrec)) { + if (!err || errno == EIO) { + err = errno; + if (err != EIO) + err = EBUSY; + } + NInoSetDirty(ni); + ntfs_log_perror("MFT record sync failed, inode %lld", + (long long)ni->mft_no); + } + } + + /* If this is a base inode with extents write all dirty extents, too. */ + if (ni->nr_extents > 0) { + s32 i; + + for (i = 0; i < ni->nr_extents; ++i) { + ntfs_inode *eni; + + eni = ni->extent_nis[i]; + if (!NInoTestAndClearDirty(eni)) + continue; + + if (ntfs_mft_record_write(eni->vol, eni->mft_no, + eni->mrec)) { + if (!err || errno == EIO) { + err = errno; + if (err != EIO) + err = EBUSY; + } + NInoSetDirty(eni); + ntfs_log_perror("Extent MFT record sync failed," + " inode %lld/%lld", + (long long)ni->mft_no, + (long long)eni->mft_no); + } + } + } + + if (err) { + errno = err; + ret = -1; + } + + ntfs_log_leave("\n"); + return ret; +} + +int ntfs_inode_sync(ntfs_inode *ni) +{ + return (ntfs_inode_sync_in_dir(ni, (ntfs_inode*)NULL)); +} + +/* + * Close an inode with an open parent inode + */ + +int ntfs_inode_close_in_dir(ntfs_inode *ni, ntfs_inode *dir_ni) +{ + int res; + + res = ntfs_inode_sync_in_dir(ni, dir_ni); + if (res) { + if (errno != EIO) + errno = EBUSY; + } else + res = ntfs_inode_close(ni); + return (res); +} + +/** + * ntfs_inode_add_attrlist - add attribute list to inode and fill it + * @ni: opened ntfs inode to which add attribute list + * + * Return 0 on success or -1 on error with errno set to the error code. + * The following error codes are defined: + * EINVAL - Invalid arguments were passed to the function. + * EEXIST - Attribute list already exist. + * EIO - Input/Ouput error occurred. + * ENOMEM - Not enough memory to perform add. + */ +int ntfs_inode_add_attrlist(ntfs_inode *ni) +{ + int err; + ntfs_attr_search_ctx *ctx; + u8 *al = NULL, *aln; + int al_len = 0; + ATTR_LIST_ENTRY *ale = NULL; + ntfs_attr *na; + + if (!ni) { + errno = EINVAL; + ntfs_log_perror("%s", __FUNCTION__); + return -1; + } + + ntfs_log_trace("inode %llu\n", (unsigned long long) ni->mft_no); + + if (NInoAttrList(ni) || ni->nr_extents) { + errno = EEXIST; + ntfs_log_perror("Inode already has attribute list"); + return -1; + } + + /* Form attribute list. */ + ctx = ntfs_attr_get_search_ctx(ni, NULL); + if (!ctx) { + err = errno; + goto err_out; + } + /* Walk through all attributes. */ + while (!ntfs_attr_lookup(AT_UNUSED, NULL, 0, 0, 0, NULL, 0, ctx)) { + + int ale_size; + + if (ctx->attr->type == AT_ATTRIBUTE_LIST) { + err = EIO; + ntfs_log_perror("Attribute list already present"); + goto put_err_out; + } + + ale_size = (sizeof(ATTR_LIST_ENTRY) + sizeof(ntfschar) * + ctx->attr->name_length + 7) & ~7; + al_len += ale_size; + + aln = realloc(al, al_len); + if (!aln) { + err = errno; + ntfs_log_perror("Failed to realloc %d bytes", al_len); + goto put_err_out; + } + ale = (ATTR_LIST_ENTRY *)(aln + ((u8 *)ale - al)); + al = aln; + + memset(ale, 0, ale_size); + + /* Add attribute to attribute list. */ + ale->type = ctx->attr->type; + ale->length = cpu_to_le16((sizeof(ATTR_LIST_ENTRY) + + sizeof(ntfschar) * ctx->attr->name_length + 7) & ~7); + ale->name_length = ctx->attr->name_length; + ale->name_offset = (u8 *)ale->name - (u8 *)ale; + if (ctx->attr->non_resident) + ale->lowest_vcn = ctx->attr->lowest_vcn; + else + ale->lowest_vcn = 0; + ale->mft_reference = MK_LE_MREF(ni->mft_no, + le16_to_cpu(ni->mrec->sequence_number)); + ale->instance = ctx->attr->instance; + memcpy(ale->name, (u8 *)ctx->attr + + le16_to_cpu(ctx->attr->name_offset), + ctx->attr->name_length * sizeof(ntfschar)); + ale = (ATTR_LIST_ENTRY *)(al + al_len); + } + /* Check for real error occurred. */ + if (errno != ENOENT) { + err = errno; + ntfs_log_perror("%s: Attribute lookup failed, inode %lld", + __FUNCTION__, (long long)ni->mft_no); + goto put_err_out; + } + + /* Set in-memory attribute list. */ + ni->attr_list = al; + ni->attr_list_size = al_len; + NInoSetAttrList(ni); + NInoAttrListSetDirty(ni); + + /* Free space if there is not enough it for $ATTRIBUTE_LIST. */ + if (le32_to_cpu(ni->mrec->bytes_allocated) - + le32_to_cpu(ni->mrec->bytes_in_use) < + offsetof(ATTR_RECORD, resident_end)) { + if (ntfs_inode_free_space(ni, + offsetof(ATTR_RECORD, resident_end))) { + /* Failed to free space. */ + err = errno; + ntfs_log_perror("Failed to free space for attrlist"); + goto rollback; + } + } + + /* Add $ATTRIBUTE_LIST to mft record. */ + if (ntfs_resident_attr_record_add(ni, + AT_ATTRIBUTE_LIST, NULL, 0, NULL, 0, 0) < 0) { + err = errno; + ntfs_log_perror("Couldn't add $ATTRIBUTE_LIST to MFT"); + goto rollback; + } + + /* Resize it. */ + na = ntfs_attr_open(ni, AT_ATTRIBUTE_LIST, AT_UNNAMED, 0); + if (!na) { + err = errno; + ntfs_log_perror("Failed to open just added $ATTRIBUTE_LIST"); + goto remove_attrlist_record; + } + if (ntfs_attr_truncate(na, al_len)) { + err = errno; + ntfs_log_perror("Failed to resize just added $ATTRIBUTE_LIST"); + ntfs_attr_close(na); + goto remove_attrlist_record;; + } + + ntfs_attr_put_search_ctx(ctx); + ntfs_attr_close(na); + return 0; + +remove_attrlist_record: + /* Prevent ntfs_attr_recorm_rm from freeing attribute list. */ + ni->attr_list = NULL; + NInoClearAttrList(ni); + /* Remove $ATTRIBUTE_LIST record. */ + ntfs_attr_reinit_search_ctx(ctx); + if (!ntfs_attr_lookup(AT_ATTRIBUTE_LIST, NULL, 0, + CASE_SENSITIVE, 0, NULL, 0, ctx)) { + if (ntfs_attr_record_rm(ctx)) + ntfs_log_perror("Rollback failed to remove attrlist"); + } else + ntfs_log_perror("Rollback failed to find attrlist"); + /* Setup back in-memory runlist. */ + ni->attr_list = al; + ni->attr_list_size = al_len; + NInoSetAttrList(ni); +rollback: + /* + * Scan attribute list for attributes that placed not in the base MFT + * record and move them to it. + */ + ntfs_attr_reinit_search_ctx(ctx); + ale = (ATTR_LIST_ENTRY*)al; + while ((u8*)ale < al + al_len) { + if (MREF_LE(ale->mft_reference) != ni->mft_no) { + if (!ntfs_attr_lookup(ale->type, ale->name, + ale->name_length, + CASE_SENSITIVE, + sle64_to_cpu(ale->lowest_vcn), + NULL, 0, ctx)) { + if (ntfs_attr_record_move_to(ctx, ni)) + ntfs_log_perror("Rollback failed to " + "move attribute"); + } else + ntfs_log_perror("Rollback failed to find attr"); + ntfs_attr_reinit_search_ctx(ctx); + } + ale = (ATTR_LIST_ENTRY*)((u8*)ale + le16_to_cpu(ale->length)); + } + /* Remove in-memory attribute list. */ + ni->attr_list = NULL; + ni->attr_list_size = 0; + NInoClearAttrList(ni); + NInoAttrListClearDirty(ni); +put_err_out: + ntfs_attr_put_search_ctx(ctx); +err_out: + free(al); + errno = err; + return -1; +} + +/** + * ntfs_inode_free_space - free space in the MFT record of an inode + * @ni: ntfs inode in which MFT record needs more free space + * @size: amount of space needed to free + * + * Return 0 on success or -1 on error with errno set to the error code. + */ +int ntfs_inode_free_space(ntfs_inode *ni, int size) +{ + ntfs_attr_search_ctx *ctx; + int freed; + + if (!ni || size < 0) { + errno = EINVAL; + ntfs_log_perror("%s: ni=%p size=%d", __FUNCTION__, ni, size); + return -1; + } + + ntfs_log_trace("Entering for inode %lld, size %d\n", + (unsigned long long)ni->mft_no, size); + + freed = (le32_to_cpu(ni->mrec->bytes_allocated) - + le32_to_cpu(ni->mrec->bytes_in_use)); + + if (size <= freed) + return 0; + + ctx = ntfs_attr_get_search_ctx(ni, NULL); + if (!ctx) + return -1; + /* + * $STANDARD_INFORMATION and $ATTRIBUTE_LIST must stay in the base MFT + * record, so position search context on the first attribute after them. + */ + if (ntfs_attr_position(AT_FILE_NAME, ctx)) + goto put_err_out; + + while (1) { + int record_size; + /* + * Check whether attribute is from different MFT record. If so, + * find next, because we don't need such. + */ + while (ctx->ntfs_ino->mft_no != ni->mft_no) { +retry: + if (ntfs_attr_position(AT_UNUSED, ctx)) + goto put_err_out; + } + + if (ntfs_inode_base(ctx->ntfs_ino)->mft_no == FILE_MFT && + ctx->attr->type == AT_DATA) + goto retry; + + if (ctx->attr->type == AT_INDEX_ROOT) + goto retry; + + record_size = le32_to_cpu(ctx->attr->length); + + if (ntfs_attr_record_move_away(ctx, 0)) { + ntfs_log_perror("Failed to move out attribute #2"); + break; + } + freed += record_size; + + /* Check whether we are done. */ + if (size <= freed) { + ntfs_attr_put_search_ctx(ctx); + return 0; + } + /* + * Reposition to first attribute after $STANDARD_INFORMATION + * and $ATTRIBUTE_LIST instead of simply skipping this attribute + * because in the case when we have got only in-memory attribute + * list then ntfs_attr_lookup will fail when it tries to find + * $ATTRIBUTE_LIST. + */ + ntfs_attr_reinit_search_ctx(ctx); + if (ntfs_attr_position(AT_FILE_NAME, ctx)) + break; + } +put_err_out: + ntfs_attr_put_search_ctx(ctx); + if (errno == ENOSPC) + ntfs_log_trace("No attributes left that could be moved out.\n"); + return -1; +} + +/** + * ntfs_inode_update_times - update selected time fields for ntfs inode + * @ni: ntfs inode for which update time fields + * @mask: select which time fields should be updated + * + * This function updates time fields to current time. Fields to update are + * selected using @mask (see enum @ntfs_time_update_flags for posssible values). + */ +void ntfs_inode_update_times(ntfs_inode *ni, ntfs_time_update_flags mask) +{ + ntfs_time now; + + if (!ni) { + ntfs_log_error("%s(): Invalid arguments.\n", __FUNCTION__); + return; + } + + if ((ni->mft_no < FILE_first_user && ni->mft_no != FILE_root) || + NVolReadOnly(ni->vol) || !mask) + return; + + now = ntfs_current_time(); + if (mask & NTFS_UPDATE_ATIME) + ni->last_access_time = now; + if (mask & NTFS_UPDATE_MTIME) + ni->last_data_change_time = now; + if (mask & NTFS_UPDATE_CTIME) + ni->last_mft_change_time = now; + + NInoFileNameSetDirty(ni); + NInoSetDirty(ni); +} + +/** + * ntfs_inode_badclus_bad - check for $Badclus:$Bad data attribute + * @mft_no: mft record number where @attr is present + * @attr: attribute record used to check for the $Bad attribute + * + * Check if the mft record given by @mft_no and @attr contains the bad sector + * list. Please note that mft record numbers describing $Badclus extent inodes + * will not match the current $Badclus:$Bad check. + * + * On success return 1 if the file is $Badclus:$Bad, otherwise return 0. + * On error return -1 with errno set to the error code. + */ +int ntfs_inode_badclus_bad(u64 mft_no, ATTR_RECORD *attr) +{ + int len, ret = 0; + ntfschar *ustr; + + if (!attr) { + ntfs_log_error("Invalid argument.\n"); + errno = EINVAL; + return -1; + } + + if (mft_no != FILE_BadClus) + return 0; + + if (attr->type != AT_DATA) + return 0; + + if ((ustr = ntfs_str2ucs("$Bad", &len)) == NULL) { + ntfs_log_perror("Couldn't convert '$Bad' to Unicode"); + return -1; + } + + if (ustr && ntfs_names_are_equal(ustr, len, + (ntfschar *)((u8 *)attr + le16_to_cpu(attr->name_offset)), + attr->name_length, 0, NULL, 0)) + ret = 1; + + ntfs_ucsfree(ustr); + + return ret; +} + +#ifdef HAVE_SETXATTR /* extended attributes interface required */ + +/* + * Get high precision NTFS times + * + * They are returned in following order : create, update, access, change + * provided they fit in requested size. + * + * Returns the modified size if successfull (or 32 if buffer size is null) + * -errno if failed + */ + +int ntfs_inode_get_times(ntfs_inode *ni, char *value, size_t size) +{ + ntfs_attr_search_ctx *ctx; + STANDARD_INFORMATION *std_info; + u64 *times; + int ret; + + ret = 0; + ctx = ntfs_attr_get_search_ctx(ni, NULL); + if (ctx) { + if (ntfs_attr_lookup(AT_STANDARD_INFORMATION, AT_UNNAMED, + 0, CASE_SENSITIVE, 0, NULL, 0, ctx)) { + ntfs_log_perror("Failed to get standard info (inode %lld)", + (long long)ni->mft_no); + } else { + std_info = (STANDARD_INFORMATION *)((u8 *)ctx->attr + + le16_to_cpu(ctx->attr->value_offset)); + if (value && (size >= 8)) { + times = (u64*)value; + times[0] = le64_to_cpu(std_info->creation_time); + ret = 8; + if (size >= 16) { + times[1] = le64_to_cpu(std_info->last_data_change_time); + ret = 16; + } + if (size >= 24) { + times[2] = le64_to_cpu(std_info->last_access_time); + ret = 24; + } + if (size >= 32) { + times[3] = le64_to_cpu(std_info->last_mft_change_time); + ret = 32; + } + } else + if (!size) + ret = 32; + else + ret = -ERANGE; + } + ntfs_attr_put_search_ctx(ctx); + } + return (ret ? ret : -errno); +} + +/* + * Set high precision NTFS times + * + * They are expected in this order : create, update, access + * provided they are present in input. The change time is set to + * current time. + * + * The times are inserted directly in the standard_information and + * file names attributes to avoid manipulating low precision times + * + * Returns 0 if success + * -1 if there were an error (described by errno) + */ + +int ntfs_inode_set_times(ntfs_inode *ni, const char *value, size_t size, + int flags) +{ + ntfs_attr_search_ctx *ctx; + STANDARD_INFORMATION *std_info; + FILE_NAME_ATTR *fn; + const u64 *times; + ntfs_time now; + int cnt; + int ret; + + ret = -1; + if ((size >= 8) && !(flags & XATTR_CREATE)) { + times = (const u64*)value; + now = ntfs_current_time(); + /* update the standard information attribute */ + ctx = ntfs_attr_get_search_ctx(ni, NULL); + if (ctx) { + if (ntfs_attr_lookup(AT_STANDARD_INFORMATION, + AT_UNNAMED, 0, CASE_SENSITIVE, + 0, NULL, 0, ctx)) { + ntfs_log_perror("Failed to get standard info (inode %lld)", + (long long)ni->mft_no); + } else { + std_info = (STANDARD_INFORMATION *)((u8 *)ctx->attr + + le16_to_cpu(ctx->attr->value_offset)); + /* + * Mark times set to avoid overwriting + * them when the inode is closed. + * The inode structure must also be updated + * (with loss of precision) because of cacheing. + * TODO : use NTFS precision in inode, and + * return sub-second times in getattr() + */ + set_nino_flag(ni, TimesSet); + std_info->creation_time = cpu_to_le64(times[0]); + ni->creation_time + = std_info->creation_time; + if (size >= 16) { + std_info->last_data_change_time = cpu_to_le64(times[1]); + ni->last_data_change_time + = std_info->last_data_change_time; + } + if (size >= 24) { + std_info->last_access_time = cpu_to_le64(times[2]); + ni->last_access_time + = std_info->last_access_time; + } + std_info->last_mft_change_time = now; + ni->last_mft_change_time = now; + ntfs_inode_mark_dirty(ctx->ntfs_ino); + NInoFileNameSetDirty(ni); + + /* update the file names attributes */ + ntfs_attr_reinit_search_ctx(ctx); + cnt = 0; + while (!ntfs_attr_lookup(AT_FILE_NAME, + AT_UNNAMED, 0, CASE_SENSITIVE, + 0, NULL, 0, ctx)) { + fn = (FILE_NAME_ATTR*)((u8 *)ctx->attr + + le16_to_cpu(ctx->attr->value_offset)); + fn->creation_time + = cpu_to_le64(times[0]); + if (size >= 16) + fn->last_data_change_time + = cpu_to_le64(times[1]); + if (size >= 24) + fn->last_access_time + = cpu_to_le64(times[2]); + fn->last_mft_change_time = now; + cnt++; + } + if (cnt) + ret = 0; + else { + ntfs_log_perror("Failed to get file names (inode %lld)", + (long long)ni->mft_no); + } + } + ntfs_attr_put_search_ctx(ctx); + } + } else + if (size < 8) + errno = ERANGE; + else + errno = EEXIST; + return (ret); +} + +#endif /* HAVE_SETXATTR */ diff --git a/libntfs-3g/lcnalloc.c b/libntfs-3g/lcnalloc.c new file mode 100755 index 0000000..9eb907c --- a/dev/null +++ b/libntfs-3g/lcnalloc.c @@ -0,0 +1,735 @@ +/** + * lcnalloc.c - Cluster (de)allocation code. Originated from the Linux-NTFS project. + * + * Copyright (c) 2002-2004 Anton Altaparmakov + * Copyright (c) 2004 Yura Pakhuchiy + * Copyright (c) 2004-2008 Szabolcs Szakacsits + * Copyright (c) 2008-2009 Jean-Pierre Andre + * + * This program/include file 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/include file 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 (in the main directory of the NTFS-3G + * distribution in the file COPYING); if not, write to the Free Software + * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STDIO_H +#include +#endif +#ifdef HAVE_ERRNO_H +#include +#endif + +#include "types.h" +#include "attrib.h" +#include "bitmap.h" +#include "debug.h" +#include "runlist.h" +#include "volume.h" +#include "lcnalloc.h" +#include "logging.h" +#include "misc.h" + +/* + * Plenty possibilities for big optimizations all over in the cluster + * allocation, however at the moment the dominant bottleneck (~ 90%) is + * the update of the mapping pairs which converges to the cubic Faulhaber's + * formula as the function of the number of extents (fragments, runs). + */ +#define NTFS_LCNALLOC_BSIZE 4096 +#define NTFS_LCNALLOC_SKIP NTFS_LCNALLOC_BSIZE + +enum { + ZONE_MFT = 1, + ZONE_DATA1 = 2, + ZONE_DATA2 = 4 +} ; + +static void ntfs_cluster_set_zone_pos(LCN start, LCN end, LCN *pos, LCN tc) +{ + ntfs_log_trace("pos: %lld tc: %lld\n", (long long)*pos, (long long)tc); + + if (tc >= end) + *pos = start; + else if (tc >= start) + *pos = tc; +} + +static void ntfs_cluster_update_zone_pos(ntfs_volume *vol, u8 zone, LCN tc) +{ + ntfs_log_trace("tc = %lld, zone = %d\n", (long long)tc, zone); + + if (zone == ZONE_MFT) + ntfs_cluster_set_zone_pos(vol->mft_lcn, vol->mft_zone_end, + &vol->mft_zone_pos, tc); + else if (zone == ZONE_DATA1) + ntfs_cluster_set_zone_pos(vol->mft_zone_end, vol->nr_clusters, + &vol->data1_zone_pos, tc); + else /* zone == ZONE_DATA2 */ + ntfs_cluster_set_zone_pos(0, vol->mft_zone_start, + &vol->data2_zone_pos, tc); +} + +/* + * Unmark full zones when a cluster has been freed in a full zone + * + * Next allocation will reuse the freed cluster + */ + +static void update_full_status(ntfs_volume *vol, LCN lcn) +{ + if (lcn >= vol->mft_zone_end) { + if (vol->full_zones & ZONE_DATA1) { + ntfs_cluster_update_zone_pos(vol, ZONE_DATA1, lcn); + vol->full_zones &= ~ZONE_DATA1; + } + } else + if (lcn < vol->mft_zone_start) { + if (vol->full_zones & ZONE_DATA2) { + ntfs_cluster_update_zone_pos(vol, ZONE_DATA2, lcn); + vol->full_zones &= ~ZONE_DATA2; + } + } else { + if (vol->full_zones & ZONE_MFT) { + ntfs_cluster_update_zone_pos(vol, ZONE_MFT, lcn); + vol->full_zones &= ~ZONE_MFT; + } + } +} + +static s64 max_empty_bit_range(unsigned char *buf, int size) +{ + int i, j, run = 0; + int max_range = 0; + s64 start_pos = -1; + + ntfs_log_trace("Entering\n"); + + i = 0; + while (i < size) { + switch (*buf) { + case 0 : + do { + buf++; + run += 8; + i++; + } while ((i < size) && !*buf); + break; + case 255 : + if (run > max_range) { + max_range = run; + start_pos = (s64)i * 8 - run; + } + run = 0; + do { + buf++; + i++; + } while ((i < size) && (*buf == 255)); + break; + default : + for (j = 0; j < 8; j++) { + + int bit = *buf & (1 << j); + + if (bit) { + if (run > max_range) { + max_range = run; + start_pos = (s64)i * 8 + (j - run); + } + run = 0; + } else + run++; + } + i++; + buf++; + + } + } + + if (run > max_range) + start_pos = (s64)i * 8 - run; + + return start_pos; +} + +static int bitmap_writeback(ntfs_volume *vol, s64 pos, s64 size, void *b, + u8 *writeback) +{ + s64 written; + + ntfs_log_trace("Entering\n"); + + if (!*writeback) + return 0; + + *writeback = 0; + + written = ntfs_attr_pwrite(vol->lcnbmp_na, pos, size, b); + if (written != size) { + if (!written) + errno = EIO; + ntfs_log_perror("Bitmap write error (%lld, %lld)", + (long long)pos, (long long)size); + return -1; + } + + return 0; +} + +/** + * ntfs_cluster_alloc - allocate clusters on an ntfs volume + * @vol: mounted ntfs volume on which to allocate the clusters + * @start_vcn: vcn to use for the first allocated cluster + * @count: number of clusters to allocate + * @start_lcn: starting lcn at which to allocate the clusters (or -1 if none) + * @zone: zone from which to allocate the clusters + * + * Allocate @count clusters preferably starting at cluster @start_lcn or at the + * current allocator position if @start_lcn is -1, on the mounted ntfs volume + * @vol. @zone is either DATA_ZONE for allocation of normal clusters and + * MFT_ZONE for allocation of clusters for the master file table, i.e. the + * $MFT/$DATA attribute. + * + * On success return a runlist describing the allocated cluster(s). + * + * On error return NULL with errno set to the error code. + * + * Notes on the allocation algorithm + * ================================= + * + * There are two data zones. First is the area between the end of the mft zone + * and the end of the volume, and second is the area between the start of the + * volume and the start of the mft zone. On unmodified/standard NTFS 1.x + * volumes, the second data zone doesn't exist due to the mft zone being + * expanded to cover the start of the volume in order to reserve space for the + * mft bitmap attribute. + * + * The complexity stems from the need of implementing the mft vs data zoned + * approach and from the fact that we have access to the lcn bitmap via up to + * NTFS_LCNALLOC_BSIZE bytes at a time, so we need to cope with crossing over + * boundaries of two buffers. Further, the fact that the allocator allows for + * caller supplied hints as to the location of where allocation should begin + * and the fact that the allocator keeps track of where in the data zones the + * next natural allocation should occur, contribute to the complexity of the + * function. But it should all be worthwhile, because this allocator: + * 1) implements MFT zone reservation + * 2) causes reduction in fragmentation. + * The code is not optimized for speed. + */ +runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count, + LCN start_lcn, const NTFS_CLUSTER_ALLOCATION_ZONES zone) +{ + LCN zone_start, zone_end; /* current search range */ + LCN last_read_pos, lcn; + LCN bmp_pos; /* current bit position inside the bitmap */ + LCN prev_lcn = 0, prev_run_len = 0; + s64 clusters, br; + runlist *rl = NULL, *trl; + u8 *buf, *byte, bit, writeback; + u8 pass = 1; /* 1: inside zone; 2: start of zone */ + u8 search_zone; /* 4: data2 (start) 1: mft (middle) 2: data1 (end) */ + u8 done_zones = 0; + u8 has_guess, used_zone_pos; + int err = 0, rlpos, rlsize, buf_size; + + ntfs_log_enter("Entering with count = 0x%llx, start_lcn = 0x%llx, " + "zone = %s_ZONE.\n", (long long)count, (long long) + start_lcn, zone == MFT_ZONE ? "MFT" : "DATA"); + + if (!vol || count < 0 || start_lcn < -1 || !vol->lcnbmp_na || + (s8)zone < FIRST_ZONE || zone > LAST_ZONE) { + errno = EINVAL; + ntfs_log_perror("%s: vcn: %lld, count: %lld, lcn: %lld", + __FUNCTION__, (long long)start_vcn, + (long long)count, (long long)start_lcn); + goto out; + } + + /* Return empty runlist if @count == 0 */ + if (!count) { + rl = ntfs_malloc(0x1000); + if (rl) { + rl[0].vcn = start_vcn; + rl[0].lcn = LCN_RL_NOT_MAPPED; + rl[0].length = 0; + } + goto out; + } + + buf = ntfs_malloc(NTFS_LCNALLOC_BSIZE); + if (!buf) + goto out; + /* + * If no @start_lcn was requested, use the current zone + * position otherwise use the requested @start_lcn. + */ + has_guess = 1; + zone_start = start_lcn; + + if (zone_start < 0) { + if (zone == DATA_ZONE) + zone_start = vol->data1_zone_pos; + else + zone_start = vol->mft_zone_pos; + has_guess = 0; + } + + used_zone_pos = has_guess ? 0 : 1; + + if (!zone_start || zone_start == vol->mft_zone_start || + zone_start == vol->mft_zone_end) + pass = 2; + + if (zone_start < vol->mft_zone_start) { + zone_end = vol->mft_zone_start; + search_zone = ZONE_DATA2; + } else if (zone_start < vol->mft_zone_end) { + zone_end = vol->mft_zone_end; + search_zone = ZONE_MFT; + } else { + zone_end = vol->nr_clusters; + search_zone = ZONE_DATA1; + } + + bmp_pos = zone_start; + + /* Loop until all clusters are allocated. */ + clusters = count; + rlpos = rlsize = 0; + while (1) { + /* check whether we have exhausted the current zone */ + if (search_zone & vol->full_zones) + goto zone_pass_done; + last_read_pos = bmp_pos >> 3; + br = ntfs_attr_pread(vol->lcnbmp_na, last_read_pos, + NTFS_LCNALLOC_BSIZE, buf); + if (br <= 0) { + if (!br) + goto zone_pass_done; + err = errno; + ntfs_log_perror("Reading $BITMAP failed"); + goto err_ret; + } + /* + * We might have read less than NTFS_LCNALLOC_BSIZE bytes + * if we are close to the end of the attribute. + */ + buf_size = (int)br << 3; + lcn = bmp_pos & 7; + bmp_pos &= ~7; + writeback = 0; + + while (lcn < buf_size) { + byte = buf + (lcn >> 3); + bit = 1 << (lcn & 7); + if (has_guess) { + if (*byte & bit) { + has_guess = 0; + break; + } + } else { + lcn = max_empty_bit_range(buf, br); + if (lcn < 0) + break; + has_guess = 1; + continue; + } + + /* First free bit is at lcn + bmp_pos. */ + + /* Reallocate memory if necessary. */ + if ((rlpos + 2) * (int)sizeof(runlist) >= rlsize) { + rlsize += 4096; + trl = realloc(rl, rlsize); + if (!trl) { + err = ENOMEM; + ntfs_log_perror("realloc() failed"); + goto wb_err_ret; + } + rl = trl; + } + + /* Allocate the bitmap bit. */ + *byte |= bit; + writeback = 1; + if (vol->free_clusters <= 0) + ntfs_log_error("Non-positive free clusters " + "(%lld)!\n", + (long long)vol->free_clusters); + else + vol->free_clusters--; + + /* + * Coalesce with previous run if adjacent LCNs. + * Otherwise, append a new run. + */ + if (prev_lcn == lcn + bmp_pos - prev_run_len && rlpos) { + ntfs_log_debug("Cluster coalesce: prev_lcn: " + "%lld lcn: %lld bmp_pos: %lld " + "prev_run_len: %lld\n", + (long long)prev_lcn, + (long long)lcn, (long long)bmp_pos, + (long long)prev_run_len); + rl[rlpos - 1].length = ++prev_run_len; + } else { + if (rlpos) + rl[rlpos].vcn = rl[rlpos - 1].vcn + + prev_run_len; + else { + rl[rlpos].vcn = start_vcn; + ntfs_log_debug("Start_vcn: %lld\n", + (long long)start_vcn); + } + + rl[rlpos].lcn = prev_lcn = lcn + bmp_pos; + rl[rlpos].length = prev_run_len = 1; + rlpos++; + } + + ntfs_log_debug("RUN: %-16lld %-16lld %-16lld\n", + (long long)rl[rlpos - 1].vcn, + (long long)rl[rlpos - 1].lcn, + (long long)rl[rlpos - 1].length); + /* Done? */ + if (!--clusters) { + if (used_zone_pos) + ntfs_cluster_update_zone_pos(vol, + search_zone, lcn + bmp_pos + 1 + + NTFS_LCNALLOC_SKIP); + goto done_ret; + } + + lcn++; + } + + if (bitmap_writeback(vol, last_read_pos, br, buf, &writeback)) { + err = errno; + goto err_ret; + } + + if (!used_zone_pos) { + + used_zone_pos = 1; + + if (search_zone == ZONE_MFT) + zone_start = vol->mft_zone_pos; + else if (search_zone == ZONE_DATA1) + zone_start = vol->data1_zone_pos; + else + zone_start = vol->data2_zone_pos; + + if (!zone_start || zone_start == vol->mft_zone_start || + zone_start == vol->mft_zone_end) + pass = 2; + bmp_pos = zone_start; + } else + bmp_pos += buf_size; + + if (bmp_pos < zone_end) + continue; + +zone_pass_done: + ntfs_log_trace("Finished current zone pass(%i).\n", pass); + if (pass == 1) { + pass = 2; + zone_end = zone_start; + + if (search_zone == ZONE_MFT) + zone_start = vol->mft_zone_start; + else if (search_zone == ZONE_DATA1) + zone_start = vol->mft_zone_end; + else + zone_start = 0; + + /* Sanity check. */ + if (zone_end < zone_start) + zone_end = zone_start; + + bmp_pos = zone_start; + + continue; + } + /* pass == 2 */ +done_zones_check: + done_zones |= search_zone; + vol->full_zones |= search_zone; + if (done_zones < (ZONE_MFT + ZONE_DATA1 + ZONE_DATA2)) { + ntfs_log_trace("Switching zone.\n"); + pass = 1; + if (rlpos) { + LCN tc = rl[rlpos - 1].lcn + + rl[rlpos - 1].length + NTFS_LCNALLOC_SKIP; + + if (used_zone_pos) + ntfs_cluster_update_zone_pos(vol, + search_zone, tc); + } + + switch (search_zone) { + case ZONE_MFT: + ntfs_log_trace("Zone switch: mft -> data1\n"); +switch_to_data1_zone: search_zone = ZONE_DATA1; + zone_start = vol->data1_zone_pos; + zone_end = vol->nr_clusters; + if (zone_start == vol->mft_zone_end) + pass = 2; + break; + case ZONE_DATA1: + ntfs_log_trace("Zone switch: data1 -> data2\n"); + search_zone = ZONE_DATA2; + zone_start = vol->data2_zone_pos; + zone_end = vol->mft_zone_start; + if (!zone_start) + pass = 2; + break; + case ZONE_DATA2: + if (!(done_zones & ZONE_DATA1)) { + ntfs_log_trace("data2 -> data1\n"); + goto switch_to_data1_zone; + } + ntfs_log_trace("Zone switch: data2 -> mft\n"); + search_zone = ZONE_MFT; + zone_start = vol->mft_zone_pos; + zone_end = vol->mft_zone_end; + if (zone_start == vol->mft_zone_start) + pass = 2; + break; + } + + bmp_pos = zone_start; + + if (zone_start == zone_end) { + ntfs_log_trace("Empty zone, skipped.\n"); + goto done_zones_check; + } + + continue; + } + + ntfs_log_trace("All zones are finished, no space on device.\n"); + err = ENOSPC; + goto err_ret; + } +done_ret: + ntfs_log_debug("At done_ret.\n"); + /* Add runlist terminator element. */ + rl[rlpos].vcn = rl[rlpos - 1].vcn + rl[rlpos - 1].length; + rl[rlpos].lcn = LCN_RL_NOT_MAPPED; + rl[rlpos].length = 0; + if (bitmap_writeback(vol, last_read_pos, br, buf, &writeback)) { + err = errno; + goto err_ret; + } +done_err_ret: + free(buf); + if (err) { + errno = err; + ntfs_log_perror("Failed to allocate clusters"); + rl = NULL; + } +out: + ntfs_log_leave("\n"); + return rl; + +wb_err_ret: + ntfs_log_trace("At wb_err_ret.\n"); + if (bitmap_writeback(vol, last_read_pos, br, buf, &writeback)) + err = errno; +err_ret: + ntfs_log_trace("At err_ret.\n"); + if (rl) { + /* Add runlist terminator element. */ + rl[rlpos].vcn = rl[rlpos - 1].vcn + rl[rlpos - 1].length; + rl[rlpos].lcn = LCN_RL_NOT_MAPPED; + rl[rlpos].length = 0; + ntfs_debug_runlist_dump(rl); + ntfs_cluster_free_from_rl(vol, rl); + free(rl); + rl = NULL; + } + goto done_err_ret; +} + +/** + * ntfs_cluster_free_from_rl - free clusters from runlist + * @vol: mounted ntfs volume on which to free the clusters + * @rl: runlist from which deallocate clusters + * + * On success return 0 and on error return -1 with errno set to the error code. + */ +int ntfs_cluster_free_from_rl(ntfs_volume *vol, runlist *rl) +{ + s64 nr_freed = 0; + int ret = -1; + + ntfs_log_trace("Entering.\n"); + + for (; rl->length; rl++) { + + ntfs_log_trace("Dealloc lcn 0x%llx, len 0x%llx.\n", + (long long)rl->lcn, (long long)rl->length); + + if (rl->lcn >= 0) { + update_full_status(vol,rl->lcn); + if (ntfs_bitmap_clear_run(vol->lcnbmp_na, rl->lcn, + rl->length)) { + ntfs_log_perror("Cluster deallocation failed " + "(%lld, %lld)", + (long long)rl->lcn, + (long long)rl->length); + goto out; + } + nr_freed += rl->length ; + } + } + + ret = 0; +out: + vol->free_clusters += nr_freed; + if (vol->free_clusters > vol->nr_clusters) + ntfs_log_error("Too many free clusters (%lld > %lld)!", + (long long)vol->free_clusters, + (long long)vol->nr_clusters); + return ret; +} + +/** + * ntfs_cluster_free - free clusters on an ntfs volume + * @vol: mounted ntfs volume on which to free the clusters + * @na: attribute whose runlist describes the clusters to free + * @start_vcn: vcn in @rl at which to start freeing clusters + * @count: number of clusters to free or -1 for all clusters + * + * Free @count clusters starting at the cluster @start_vcn in the runlist + * described by the attribute @na from the mounted ntfs volume @vol. + * + * If @count is -1, all clusters from @start_vcn to the end of the runlist + * are deallocated. + * + * On success return the number of deallocated clusters (not counting sparse + * clusters) and on error return -1 with errno set to the error code. + */ +int ntfs_cluster_free(ntfs_volume *vol, ntfs_attr *na, VCN start_vcn, s64 count) +{ + runlist *rl; + s64 delta, to_free, nr_freed = 0; + int ret = -1; + + if (!vol || !vol->lcnbmp_na || !na || start_vcn < 0 || + (count < 0 && count != -1)) { + ntfs_log_trace("Invalid arguments!\n"); + errno = EINVAL; + return -1; + } + + ntfs_log_enter("Entering for inode 0x%llx, attr 0x%x, count 0x%llx, " + "vcn 0x%llx.\n", (unsigned long long)na->ni->mft_no, + na->type, (long long)count, (long long)start_vcn); + + rl = ntfs_attr_find_vcn(na, start_vcn); + if (!rl) { + if (errno == ENOENT) + ret = 0; + goto leave; + } + + if (rl->lcn < 0 && rl->lcn != LCN_HOLE) { + errno = EIO; + ntfs_log_perror("%s: Unexpected lcn (%lld)", __FUNCTION__, + (long long)rl->lcn); + goto leave; + } + + /* Find the starting cluster inside the run that needs freeing. */ + delta = start_vcn - rl->vcn; + + /* The number of clusters in this run that need freeing. */ + to_free = rl->length - delta; + if (count >= 0 && to_free > count) + to_free = count; + + if (rl->lcn != LCN_HOLE) { + /* Do the actual freeing of the clusters in this run. */ + update_full_status(vol,rl->lcn + delta); + if (ntfs_bitmap_clear_run(vol->lcnbmp_na, rl->lcn + delta, + to_free)) + goto leave; + nr_freed = to_free; + } + + /* Go to the next run and adjust the number of clusters left to free. */ + ++rl; + if (count >= 0) + count -= to_free; + + /* + * Loop over the remaining runs, using @count as a capping value, and + * free them. + */ + for (; rl->length && count != 0; ++rl) { + // FIXME: Need to try ntfs_attr_map_runlist() for attribute + // list support! (AIA) + if (rl->lcn < 0 && rl->lcn != LCN_HOLE) { + // FIXME: Eeek! We need rollback! (AIA) + errno = EIO; + ntfs_log_perror("%s: Invalid lcn (%lli)", + __FUNCTION__, (long long)rl->lcn); + goto out; + } + + /* The number of clusters in this run that need freeing. */ + to_free = rl->length; + if (count >= 0 && to_free > count) + to_free = count; + + if (rl->lcn != LCN_HOLE) { + update_full_status(vol,rl->lcn); + if (ntfs_bitmap_clear_run(vol->lcnbmp_na, rl->lcn, + to_free)) { + // FIXME: Eeek! We need rollback! (AIA) + ntfs_log_perror("%s: Clearing bitmap run failed", + __FUNCTION__); + goto out; + } + nr_freed += to_free; + } + + if (count >= 0) + count -= to_free; + } + + if (count != -1 && count != 0) { + // FIXME: Eeek! BUG() + errno = EIO; + ntfs_log_perror("%s: count still not zero (%lld)", __FUNCTION__, + (long long)count); + goto out; + } + + ret = nr_freed; +out: + vol->free_clusters += nr_freed ; + if (vol->free_clusters > vol->nr_clusters) + ntfs_log_error("Too many free clusters (%lld > %lld)!", + (long long)vol->free_clusters, + (long long)vol->nr_clusters); +leave: + ntfs_log_leave("\n"); + return ret; +} diff --git a/libntfs-3g/libntfs-3g.pc.in b/libntfs-3g/libntfs-3g.pc.in new file mode 100755 index 0000000..5f2fea7 --- a/dev/null +++ b/libntfs-3g/libntfs-3g.pc.in @@ -0,0 +1,10 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: libntfs-3g +Description: NTFS-3G Read/Write Driver Library +Version: @PACKAGE_VERSION@ +Cflags: -I${includedir} +Libs: @LIBFUSE_LITE_LIBS@ -L${libdir} -lntfs-3g diff --git a/libntfs-3g/libntfs-3g.script.so.in b/libntfs-3g/libntfs-3g.script.so.in new file mode 100755 index 0000000..d050cfa --- a/dev/null +++ b/libntfs-3g/libntfs-3g.script.so.in @@ -0,0 +1,2 @@ +@OUTPUT_FORMAT@ +GROUP ( @rootlibdir@/libntfs-3g.so ) diff --git a/libntfs-3g/logfile.c b/libntfs-3g/logfile.c new file mode 100755 index 0000000..277ad14 --- a/dev/null +++ b/libntfs-3g/logfile.c @@ -0,0 +1,737 @@ +/** + * logfile.c - NTFS journal handling. Originated from the Linux-NTFS project. + * + * Copyright (c) 2002-2005 Anton Altaparmakov + * Copyright (c) 2005 Yura Pakhuchiy + * Copyright (c) 2005-2009 Szabolcs Szakacsits + * + * This program/include file 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/include file 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 (in the main directory of the NTFS-3G + * distribution in the file COPYING); if not, write to the Free Software + * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_ERRNO_H +#include +#endif + +#include "attrib.h" +#include "debug.h" +#include "logfile.h" +#include "volume.h" +#include "mst.h" +#include "logging.h" +#include "misc.h" + +/** + * ntfs_check_restart_page_header - check the page header for consistency + * @rp: restart page header to check + * @pos: position in logfile at which the restart page header resides + * + * Check the restart page header @rp for consistency and return TRUE if it is + * consistent and FALSE otherwise. + * + * This function only needs NTFS_BLOCK_SIZE bytes in @rp, i.e. it does not + * require the full restart page. + */ +static BOOL ntfs_check_restart_page_header(RESTART_PAGE_HEADER *rp, s64 pos) +{ + u32 logfile_system_page_size, logfile_log_page_size; + u16 ra_ofs, usa_count, usa_ofs, usa_end = 0; + BOOL have_usa = TRUE; + + ntfs_log_trace("Entering.\n"); + /* + * If the system or log page sizes are smaller than the ntfs block size + * or either is not a power of 2 we cannot handle this log file. + */ + logfile_system_page_size = le32_to_cpu(rp->system_page_size); + logfile_log_page_size = le32_to_cpu(rp->log_page_size); + if (logfile_system_page_size < NTFS_BLOCK_SIZE || + logfile_log_page_size < NTFS_BLOCK_SIZE || + logfile_system_page_size & + (logfile_system_page_size - 1) || + logfile_log_page_size & (logfile_log_page_size - 1)) { + ntfs_log_error("$LogFile uses unsupported page size.\n"); + return FALSE; + } + /* + * We must be either at !pos (1st restart page) or at pos = system page + * size (2nd restart page). + */ + if (pos && pos != logfile_system_page_size) { + ntfs_log_error("Found restart area in incorrect " + "position in $LogFile.\n"); + return FALSE; + } + /* We only know how to handle version 1.1. */ + if (sle16_to_cpu(rp->major_ver) != 1 || + sle16_to_cpu(rp->minor_ver) != 1) { + ntfs_log_error("$LogFile version %i.%i is not " + "supported. (This driver supports version " + "1.1 only.)\n", (int)sle16_to_cpu(rp->major_ver), + (int)sle16_to_cpu(rp->minor_ver)); + return FALSE; + } + /* + * If chkdsk has been run the restart page may not be protected by an + * update sequence array. + */ + if (ntfs_is_chkd_record(rp->magic) && !le16_to_cpu(rp->usa_count)) { + have_usa = FALSE; + goto skip_usa_checks; + } + /* Verify the size of the update sequence array. */ + usa_count = 1 + (logfile_system_page_size >> NTFS_BLOCK_SIZE_BITS); + if (usa_count != le16_to_cpu(rp->usa_count)) { + ntfs_log_error("$LogFile restart page specifies " + "inconsistent update sequence array count.\n"); + return FALSE; + } + /* Verify the position of the update sequence array. */ + usa_ofs = le16_to_cpu(rp->usa_ofs); + usa_end = usa_ofs + usa_count * sizeof(u16); + if (usa_ofs < sizeof(RESTART_PAGE_HEADER) || + usa_end > NTFS_BLOCK_SIZE - sizeof(u16)) { + ntfs_log_error("$LogFile restart page specifies " + "inconsistent update sequence array offset.\n"); + return FALSE; + } +skip_usa_checks: + /* + * Verify the position of the restart area. It must be: + * - aligned to 8-byte boundary, + * - after the update sequence array, and + * - within the system page size. + */ + ra_ofs = le16_to_cpu(rp->restart_area_offset); + if (ra_ofs & 7 || (have_usa ? ra_ofs < usa_end : + ra_ofs < sizeof(RESTART_PAGE_HEADER)) || + ra_ofs > logfile_system_page_size) { + ntfs_log_error("$LogFile restart page specifies " + "inconsistent restart area offset.\n"); + return FALSE; + } + /* + * Only restart pages modified by chkdsk are allowed to have chkdsk_lsn + * set. + */ + if (!ntfs_is_chkd_record(rp->magic) && sle64_to_cpu(rp->chkdsk_lsn)) { + ntfs_log_error("$LogFile restart page is not modified " + "by chkdsk but a chkdsk LSN is specified.\n"); + return FALSE; + } + ntfs_log_trace("Done.\n"); + return TRUE; +} + +/** + * ntfs_check_restart_area - check the restart area for consistency + * @rp: restart page whose restart area to check + * + * Check the restart area of the restart page @rp for consistency and return + * TRUE if it is consistent and FALSE otherwise. + * + * This function assumes that the restart page header has already been + * consistency checked. + * + * This function only needs NTFS_BLOCK_SIZE bytes in @rp, i.e. it does not + * require the full restart page. + */ +static BOOL ntfs_check_restart_area(RESTART_PAGE_HEADER *rp) +{ + u64 file_size; + RESTART_AREA *ra; + u16 ra_ofs, ra_len, ca_ofs; + u8 fs_bits; + + ntfs_log_trace("Entering.\n"); + ra_ofs = le16_to_cpu(rp->restart_area_offset); + ra = (RESTART_AREA*)((u8*)rp + ra_ofs); + /* + * Everything before ra->file_size must be before the first word + * protected by an update sequence number. This ensures that it is + * safe to access ra->client_array_offset. + */ + if (ra_ofs + offsetof(RESTART_AREA, file_size) > + NTFS_BLOCK_SIZE - sizeof(u16)) { + ntfs_log_error("$LogFile restart area specifies " + "inconsistent file offset.\n"); + return FALSE; + } + /* + * Now that we can access ra->client_array_offset, make sure everything + * up to the log client array is before the first word protected by an + * update sequence number. This ensures we can access all of the + * restart area elements safely. Also, the client array offset must be + * aligned to an 8-byte boundary. + */ + ca_ofs = le16_to_cpu(ra->client_array_offset); + if (((ca_ofs + 7) & ~7) != ca_ofs || + ra_ofs + ca_ofs > (u16)(NTFS_BLOCK_SIZE - + sizeof(u16))) { + ntfs_log_error("$LogFile restart area specifies " + "inconsistent client array offset.\n"); + return FALSE; + } + /* + * The restart area must end within the system page size both when + * calculated manually and as specified by ra->restart_area_length. + * Also, the calculated length must not exceed the specified length. + */ + ra_len = ca_ofs + le16_to_cpu(ra->log_clients) * + sizeof(LOG_CLIENT_RECORD); + if ((u32)(ra_ofs + ra_len) > le32_to_cpu(rp->system_page_size) || + (u32)(ra_ofs + le16_to_cpu(ra->restart_area_length)) > + le32_to_cpu(rp->system_page_size) || + ra_len > le16_to_cpu(ra->restart_area_length)) { + ntfs_log_error("$LogFile restart area is out of bounds " + "of the system page size specified by the " + "restart page header and/or the specified " + "restart area length is inconsistent.\n"); + return FALSE; + } + /* + * The ra->client_free_list and ra->client_in_use_list must be either + * LOGFILE_NO_CLIENT or less than ra->log_clients or they are + * overflowing the client array. + */ + if ((ra->client_free_list != LOGFILE_NO_CLIENT && + le16_to_cpu(ra->client_free_list) >= + le16_to_cpu(ra->log_clients)) || + (ra->client_in_use_list != LOGFILE_NO_CLIENT && + le16_to_cpu(ra->client_in_use_list) >= + le16_to_cpu(ra->log_clients))) { + ntfs_log_error("$LogFile restart area specifies " + "overflowing client free and/or in use lists.\n"); + return FALSE; + } + /* + * Check ra->seq_number_bits against ra->file_size for consistency. + * We cannot just use ffs() because the file size is not a power of 2. + */ + file_size = (u64)sle64_to_cpu(ra->file_size); + fs_bits = 0; + while (file_size) { + file_size >>= 1; + fs_bits++; + } + if (le32_to_cpu(ra->seq_number_bits) != (u32)(67 - fs_bits)) { + ntfs_log_error("$LogFile restart area specifies " + "inconsistent sequence number bits.\n"); + return FALSE; + } + /* The log record header length must be a multiple of 8. */ + if (((le16_to_cpu(ra->log_record_header_length) + 7) & ~7) != + le16_to_cpu(ra->log_record_header_length)) { + ntfs_log_error("$LogFile restart area specifies " + "inconsistent log record header length.\n"); + return FALSE; + } + /* Ditto for the log page data offset. */ + if (((le16_to_cpu(ra->log_page_data_offset) + 7) & ~7) != + le16_to_cpu(ra->log_page_data_offset)) { + ntfs_log_error("$LogFile restart area specifies " + "inconsistent log page data offset.\n"); + return FALSE; + } + ntfs_log_trace("Done.\n"); + return TRUE; +} + +/** + * ntfs_check_log_client_array - check the log client array for consistency + * @rp: restart page whose log client array to check + * + * Check the log client array of the restart page @rp for consistency and + * return TRUE if it is consistent and FALSE otherwise. + * + * This function assumes that the restart page header and the restart area have + * already been consistency checked. + * + * Unlike ntfs_check_restart_page_header() and ntfs_check_restart_area(), this + * function needs @rp->system_page_size bytes in @rp, i.e. it requires the full + * restart page and the page must be multi sector transfer deprotected. + */ +static BOOL ntfs_check_log_client_array(RESTART_PAGE_HEADER *rp) +{ + RESTART_AREA *ra; + LOG_CLIENT_RECORD *ca, *cr; + u16 nr_clients, idx; + BOOL in_free_list, idx_is_first; + + ntfs_log_trace("Entering.\n"); + ra = (RESTART_AREA*)((u8*)rp + le16_to_cpu(rp->restart_area_offset)); + ca = (LOG_CLIENT_RECORD*)((u8*)ra + + le16_to_cpu(ra->client_array_offset)); + /* + * Check the ra->client_free_list first and then check the + * ra->client_in_use_list. Check each of the log client records in + * each of the lists and check that the array does not overflow the + * ra->log_clients value. Also keep track of the number of records + * visited as there cannot be more than ra->log_clients records and + * that way we detect eventual loops in within a list. + */ + nr_clients = le16_to_cpu(ra->log_clients); + idx = le16_to_cpu(ra->client_free_list); + in_free_list = TRUE; +check_list: + for (idx_is_first = TRUE; idx != LOGFILE_NO_CLIENT_CPU; nr_clients--, + idx = le16_to_cpu(cr->next_client)) { + if (!nr_clients || idx >= le16_to_cpu(ra->log_clients)) + goto err_out; + /* Set @cr to the current log client record. */ + cr = ca + idx; + /* The first log client record must not have a prev_client. */ + if (idx_is_first) { + if (cr->prev_client != LOGFILE_NO_CLIENT) + goto err_out; + idx_is_first = FALSE; + } + } + /* Switch to and check the in use list if we just did the free list. */ + if (in_free_list) { + in_free_list = FALSE; + idx = le16_to_cpu(ra->client_in_use_list); + goto check_list; + } + ntfs_log_trace("Done.\n"); + return TRUE; +err_out: + ntfs_log_error("$LogFile log client array is corrupt.\n"); + return FALSE; +} + +/** + * ntfs_check_and_load_restart_page - check the restart page for consistency + * @log_na: opened ntfs attribute for journal $LogFile + * @rp: restart page to check + * @pos: position in @log_na at which the restart page resides + * @wrp: [OUT] copy of the multi sector transfer deprotected restart page + * @lsn: [OUT] set to the current logfile lsn on success + * + * Check the restart page @rp for consistency and return 0 if it is consistent + * and errno otherwise. The restart page may have been modified by chkdsk in + * which case its magic is CHKD instead of RSTR. + * + * This function only needs NTFS_BLOCK_SIZE bytes in @rp, i.e. it does not + * require the full restart page. + * + * If @wrp is not NULL, on success, *@wrp will point to a buffer containing a + * copy of the complete multi sector transfer deprotected page. On failure, + * *@wrp is undefined. + * + * Similarly, if @lsn is not NULL, on success *@lsn will be set to the current + * logfile lsn according to this restart page. On failure, *@lsn is undefined. + * + * The following error codes are defined: + * EINVAL - The restart page is inconsistent. + * ENOMEM - Not enough memory to load the restart page. + * EIO - Failed to reading from $LogFile. + */ +static int ntfs_check_and_load_restart_page(ntfs_attr *log_na, + RESTART_PAGE_HEADER *rp, s64 pos, RESTART_PAGE_HEADER **wrp, + LSN *lsn) +{ + RESTART_AREA *ra; + RESTART_PAGE_HEADER *trp; + int err; + + ntfs_log_trace("Entering.\n"); + /* Check the restart page header for consistency. */ + if (!ntfs_check_restart_page_header(rp, pos)) { + /* Error output already done inside the function. */ + return EINVAL; + } + /* Check the restart area for consistency. */ + if (!ntfs_check_restart_area(rp)) { + /* Error output already done inside the function. */ + return EINVAL; + } + ra = (RESTART_AREA*)((u8*)rp + le16_to_cpu(rp->restart_area_offset)); + /* + * Allocate a buffer to store the whole restart page so we can multi + * sector transfer deprotect it. + */ + trp = ntfs_malloc(le32_to_cpu(rp->system_page_size)); + if (!trp) + return errno; + /* + * Read the whole of the restart page into the buffer. If it fits + * completely inside @rp, just copy it from there. Otherwise read it + * from disk. + */ + if (le32_to_cpu(rp->system_page_size) <= NTFS_BLOCK_SIZE) + memcpy(trp, rp, le32_to_cpu(rp->system_page_size)); + else if (ntfs_attr_pread(log_na, pos, + le32_to_cpu(rp->system_page_size), trp) != + le32_to_cpu(rp->system_page_size)) { + err = errno; + ntfs_log_error("Failed to read whole restart page into the " + "buffer.\n"); + if (err != ENOMEM) + err = EIO; + goto err_out; + } + /* + * Perform the multi sector transfer deprotection on the buffer if the + * restart page is protected. + */ + if ((!ntfs_is_chkd_record(trp->magic) || le16_to_cpu(trp->usa_count)) + && ntfs_mst_post_read_fixup((NTFS_RECORD*)trp, + le32_to_cpu(rp->system_page_size))) { + /* + * A multi sector tranfer error was detected. We only need to + * abort if the restart page contents exceed the multi sector + * transfer fixup of the first sector. + */ + if (le16_to_cpu(rp->restart_area_offset) + + le16_to_cpu(ra->restart_area_length) > + NTFS_BLOCK_SIZE - (int)sizeof(u16)) { + ntfs_log_error("Multi sector transfer error " + "detected in $LogFile restart page.\n"); + err = EINVAL; + goto err_out; + } + } + /* + * If the restart page is modified by chkdsk or there are no active + * logfile clients, the logfile is consistent. Otherwise, need to + * check the log client records for consistency, too. + */ + err = 0; + if (ntfs_is_rstr_record(rp->magic) && + ra->client_in_use_list != LOGFILE_NO_CLIENT) { + if (!ntfs_check_log_client_array(trp)) { + err = EINVAL; + goto err_out; + } + } + if (lsn) { + if (ntfs_is_rstr_record(rp->magic)) + *lsn = sle64_to_cpu(ra->current_lsn); + else /* if (ntfs_is_chkd_record(rp->magic)) */ + *lsn = sle64_to_cpu(rp->chkdsk_lsn); + } + ntfs_log_trace("Done.\n"); + if (wrp) + *wrp = trp; + else { +err_out: + free(trp); + } + return err; +} + +/** + * ntfs_check_logfile - check in the journal if the volume is consistent + * @log_na: ntfs attribute of loaded journal $LogFile to check + * @rp: [OUT] on success this is a copy of the current restart page + * + * Check the $LogFile journal for consistency and return TRUE if it is + * consistent and FALSE if not. On success, the current restart page is + * returned in *@rp. Caller must call ntfs_free(*@rp) when finished with it. + * + * At present we only check the two restart pages and ignore the log record + * pages. + * + * Note that the MstProtected flag is not set on the $LogFile inode and hence + * when reading pages they are not deprotected. This is because we do not know + * if the $LogFile was created on a system with a different page size to ours + * yet and mst deprotection would fail if our page size is smaller. + */ +BOOL ntfs_check_logfile(ntfs_attr *log_na, RESTART_PAGE_HEADER **rp) +{ + s64 size, pos; + LSN rstr1_lsn, rstr2_lsn; + ntfs_volume *vol = log_na->ni->vol; + u8 *kaddr = NULL; + RESTART_PAGE_HEADER *rstr1_ph = NULL; + RESTART_PAGE_HEADER *rstr2_ph = NULL; + int log_page_size, log_page_mask, err; + BOOL logfile_is_empty = TRUE; + u8 log_page_bits; + + ntfs_log_trace("Entering.\n"); + /* An empty $LogFile must have been clean before it got emptied. */ + if (NVolLogFileEmpty(vol)) + goto is_empty; + size = log_na->data_size; + /* Make sure the file doesn't exceed the maximum allowed size. */ + if (size > (s64)MaxLogFileSize) + size = MaxLogFileSize; + log_page_size = DefaultLogPageSize; + log_page_mask = log_page_size - 1; + /* + * Use generic_ffs() instead of ffs() to enable the compiler to + * optimize log_page_size and log_page_bits into constants. + */ + log_page_bits = ffs(log_page_size) - 1; + size &= ~(log_page_size - 1); + + /* + * Ensure the log file is big enough to store at least the two restart + * pages and the minimum number of log record pages. + */ + if (size < log_page_size * 2 || (size - log_page_size * 2) >> + log_page_bits < MinLogRecordPages) { + ntfs_log_error("$LogFile is too small.\n"); + return FALSE; + } + /* Allocate memory for restart page. */ + kaddr = ntfs_malloc(NTFS_BLOCK_SIZE); + if (!kaddr) + return FALSE; + /* + * Read through the file looking for a restart page. Since the restart + * page header is at the beginning of a page we only need to search at + * what could be the beginning of a page (for each page size) rather + * than scanning the whole file byte by byte. If all potential places + * contain empty and uninitialized records, the log file can be assumed + * to be empty. + */ + for (pos = 0; pos < size; pos <<= 1) { + /* + * Read first NTFS_BLOCK_SIZE bytes of potential restart page. + */ + if (ntfs_attr_pread(log_na, pos, NTFS_BLOCK_SIZE, kaddr) != + NTFS_BLOCK_SIZE) { + ntfs_log_error("Failed to read first NTFS_BLOCK_SIZE " + "bytes of potential restart page.\n"); + goto err_out; + } + + /* + * A non-empty block means the logfile is not empty while an + * empty block after a non-empty block has been encountered + * means we are done. + */ + if (!ntfs_is_empty_recordp((le32*)kaddr)) + logfile_is_empty = FALSE; + else if (!logfile_is_empty) + break; + /* + * A log record page means there cannot be a restart page after + * this so no need to continue searching. + */ + if (ntfs_is_rcrd_recordp((le32*)kaddr)) + break; + /* If not a (modified by chkdsk) restart page, continue. */ + if (!ntfs_is_rstr_recordp((le32*)kaddr) && + !ntfs_is_chkd_recordp((le32*)kaddr)) { + if (!pos) + pos = NTFS_BLOCK_SIZE >> 1; + continue; + } + /* + * Check the (modified by chkdsk) restart page for consistency + * and get a copy of the complete multi sector transfer + * deprotected restart page. + */ + err = ntfs_check_and_load_restart_page(log_na, + (RESTART_PAGE_HEADER*)kaddr, pos, + !rstr1_ph ? &rstr1_ph : &rstr2_ph, + !rstr1_ph ? &rstr1_lsn : &rstr2_lsn); + if (!err) { + /* + * If we have now found the first (modified by chkdsk) + * restart page, continue looking for the second one. + */ + if (!pos) { + pos = NTFS_BLOCK_SIZE >> 1; + continue; + } + /* + * We have now found the second (modified by chkdsk) + * restart page, so we can stop looking. + */ + break; + } + /* + * Error output already done inside the function. Note, we do + * not abort if the restart page was invalid as we might still + * find a valid one further in the file. + */ + if (err != EINVAL) + goto err_out; + /* Continue looking. */ + if (!pos) + pos = NTFS_BLOCK_SIZE >> 1; + } + if (kaddr) { + free(kaddr); + kaddr = NULL; + } + if (logfile_is_empty) { + NVolSetLogFileEmpty(vol); +is_empty: + ntfs_log_trace("Done. ($LogFile is empty.)\n"); + return TRUE; + } + if (!rstr1_ph) { + if (rstr2_ph) + ntfs_log_error("BUG: rstr2_ph isn't NULL!\n"); + ntfs_log_error("Did not find any restart pages in " + "$LogFile and it was not empty.\n"); + return FALSE; + } + /* If both restart pages were found, use the more recent one. */ + if (rstr2_ph) { + /* + * If the second restart area is more recent, switch to it. + * Otherwise just throw it away. + */ + if (rstr2_lsn > rstr1_lsn) { + ntfs_log_debug("Using second restart page as it is more " + "recent.\n"); + free(rstr1_ph); + rstr1_ph = rstr2_ph; + /* rstr1_lsn = rstr2_lsn; */ + } else { + ntfs_log_debug("Using first restart page as it is more " + "recent.\n"); + free(rstr2_ph); + } + rstr2_ph = NULL; + } + /* All consistency checks passed. */ + if (rp) + *rp = rstr1_ph; + else + free(rstr1_ph); + ntfs_log_trace("Done.\n"); + return TRUE; +err_out: + free(kaddr); + free(rstr1_ph); + free(rstr2_ph); + return FALSE; +} + +/** + * ntfs_is_logfile_clean - check in the journal if the volume is clean + * @log_na: ntfs attribute of loaded journal $LogFile to check + * @rp: copy of the current restart page + * + * Analyze the $LogFile journal and return TRUE if it indicates the volume was + * shutdown cleanly and FALSE if not. + * + * At present we only look at the two restart pages and ignore the log record + * pages. This is a little bit crude in that there will be a very small number + * of cases where we think that a volume is dirty when in fact it is clean. + * This should only affect volumes that have not been shutdown cleanly but did + * not have any pending, non-check-pointed i/o, i.e. they were completely idle + * at least for the five seconds preceding the unclean shutdown. + * + * This function assumes that the $LogFile journal has already been consistency + * checked by a call to ntfs_check_logfile() and in particular if the $LogFile + * is empty this function requires that NVolLogFileEmpty() is true otherwise an + * empty volume will be reported as dirty. + */ +BOOL ntfs_is_logfile_clean(ntfs_attr *log_na, RESTART_PAGE_HEADER *rp) +{ + RESTART_AREA *ra; + + ntfs_log_trace("Entering.\n"); + /* An empty $LogFile must have been clean before it got emptied. */ + if (NVolLogFileEmpty(log_na->ni->vol)) { + ntfs_log_trace("$LogFile is empty\n"); + return TRUE; + } + if (!rp) { + ntfs_log_error("Restart page header is NULL\n"); + return FALSE; + } + if (!ntfs_is_rstr_record(rp->magic) && + !ntfs_is_chkd_record(rp->magic)) { + ntfs_log_error("Restart page buffer is invalid\n"); + return FALSE; + } + + ra = (RESTART_AREA*)((u8*)rp + le16_to_cpu(rp->restart_area_offset)); + /* + * If the $LogFile has active clients, i.e. it is open, and we do not + * have the RESTART_VOLUME_IS_CLEAN bit set in the restart area flags, + * we assume there was an unclean shutdown. + */ + if (ra->client_in_use_list != LOGFILE_NO_CLIENT && + !(ra->flags & RESTART_VOLUME_IS_CLEAN)) { + ntfs_log_error("The disk contains an unclean file system (%d, " + "%d).\n", le16_to_cpu(ra->client_in_use_list), + le16_to_cpu(ra->flags)); + return FALSE; + } + /* $LogFile indicates a clean shutdown. */ + ntfs_log_trace("$LogFile indicates a clean shutdown\n"); + return TRUE; +} + +/** + * ntfs_empty_logfile - empty the contents of the $LogFile journal + * @na: ntfs attribute of journal $LogFile to empty + * + * Empty the contents of the $LogFile journal @na and return 0 on success and + * -1 on error. + * + * This function assumes that the $LogFile journal has already been consistency + * checked by a call to ntfs_check_logfile() and that ntfs_is_logfile_clean() + * has been used to ensure that the $LogFile is clean. + */ +int ntfs_empty_logfile(ntfs_attr *na) +{ + s64 pos, count; + char buf[NTFS_BUF_SIZE]; + + ntfs_log_trace("Entering.\n"); + + if (NVolLogFileEmpty(na->ni->vol)) + return 0; + + if (!NAttrNonResident(na)) { + errno = EIO; + ntfs_log_perror("Resident $LogFile $DATA attribute"); + return -1; + } + + memset(buf, -1, NTFS_BUF_SIZE); + + pos = 0; + while ((count = na->data_size - pos) > 0) { + + if (count > NTFS_BUF_SIZE) + count = NTFS_BUF_SIZE; + + count = ntfs_attr_pwrite(na, pos, count, buf); + if (count <= 0) { + ntfs_log_perror("Failed to reset $LogFile"); + if (count != -1) + errno = EIO; + return -1; + } + pos += count; + } + + NVolSetLogFileEmpty(na->ni->vol); + + return 0; +} diff --git a/libntfs-3g/logging.c b/libntfs-3g/logging.c new file mode 100755 index 0000000..385bcaa --- a/dev/null +++ b/libntfs-3g/logging.c @@ -0,0 +1,613 @@ +/** + * logging.c - Centralised logging. Originated from the Linux-NTFS project. + * + * Copyright (c) 2005 Richard Russon + * Copyright (c) 2005-2008 Szabolcs Szakacsits + * + * This program/include file 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/include file 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 (in the main directory of the NTFS-3G + * distribution in the file COPYING); if not, write to the Free Software + * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_STDIO_H +#include +#endif +#ifdef HAVE_ERRNO_H +#include +#endif +#ifdef HAVE_STDARG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_SYSLOG_H +#include +#endif + +#include "logging.h" +#include "misc.h" + +#ifndef PATH_SEP +#define PATH_SEP '/' +#endif + +#ifdef DEBUG +static int tab; +#endif + +/* Some gcc 3.x, 4.[01].X crash with internal compiler error. */ +#if __GNUC__ <= 3 || (__GNUC__ == 4 && __GNUC_MINOR__ <= 1) +# define BROKEN_GCC_FORMAT_ATTRIBUTE +#else +# define BROKEN_GCC_FORMAT_ATTRIBUTE __attribute__((format(printf, 6, 0))) +#endif + +/** + * struct ntfs_logging - Control info for the logging system + * @levels: Bitfield of logging levels + * @flags: Flags which affect the output style + * @handler: Function to perform the actual logging + */ +struct ntfs_logging { + u32 levels; + u32 flags; + ntfs_log_handler *handler BROKEN_GCC_FORMAT_ATTRIBUTE; +}; + +/** + * ntfs_log + * This struct controls all the logging within the library and tools. + */ +static struct ntfs_logging ntfs_log = { +#ifdef DEBUG + NTFS_LOG_LEVEL_DEBUG | NTFS_LOG_LEVEL_TRACE | NTFS_LOG_LEVEL_ENTER | + NTFS_LOG_LEVEL_LEAVE | +#endif + NTFS_LOG_LEVEL_INFO | NTFS_LOG_LEVEL_QUIET | NTFS_LOG_LEVEL_WARNING | + NTFS_LOG_LEVEL_ERROR | NTFS_LOG_LEVEL_PERROR | NTFS_LOG_LEVEL_CRITICAL | + NTFS_LOG_LEVEL_PROGRESS, + NTFS_LOG_FLAG_ONLYNAME, +#ifdef DEBUG + ntfs_log_handler_outerr +#else + ntfs_log_handler_null +#endif +}; + + +/** + * ntfs_log_get_levels - Get a list of the current logging levels + * + * Find out which logging levels are enabled. + * + * Returns: Log levels in a 32-bit field + */ +u32 ntfs_log_get_levels(void) +{ + return ntfs_log.levels; +} + +/** + * ntfs_log_set_levels - Enable extra logging levels + * @levels: 32-bit field of log levels to set + * + * Enable one or more logging levels. + * The logging levels are named: NTFS_LOG_LEVEL_*. + * + * Returns: Log levels that were enabled before the call + */ +u32 ntfs_log_set_levels(u32 levels) +{ + u32 old; + old = ntfs_log.levels; + ntfs_log.levels |= levels; + return old; +} + +/** + * ntfs_log_clear_levels - Disable some logging levels + * @levels: 32-bit field of log levels to clear + * + * Disable one or more logging levels. + * The logging levels are named: NTFS_LOG_LEVEL_*. + * + * Returns: Log levels that were enabled before the call + */ +u32 ntfs_log_clear_levels(u32 levels) +{ + u32 old; + old = ntfs_log.levels; + ntfs_log.levels &= (~levels); + return old; +} + + +/** + * ntfs_log_get_flags - Get a list of logging style flags + * + * Find out which logging flags are enabled. + * + * Returns: Logging flags in a 32-bit field + */ +u32 ntfs_log_get_flags(void) +{ + return ntfs_log.flags; +} + +/** + * ntfs_log_set_flags - Enable extra logging style flags + * @flags: 32-bit field of logging flags to set + * + * Enable one or more logging flags. + * The log flags are named: NTFS_LOG_LEVEL_*. + * + * Returns: Logging flags that were enabled before the call + */ +u32 ntfs_log_set_flags(u32 flags) +{ + u32 old; + old = ntfs_log.flags; + ntfs_log.flags |= flags; + return old; +} + +/** + * ntfs_log_clear_flags - Disable some logging styles + * @flags: 32-bit field of logging flags to clear + * + * Disable one or more logging flags. + * The log flags are named: NTFS_LOG_LEVEL_*. + * + * Returns: Logging flags that were enabled before the call + */ +u32 ntfs_log_clear_flags(u32 flags) +{ + u32 old; + old = ntfs_log.flags; + ntfs_log.flags &= (~flags); + return old; +} + + +/** + * ntfs_log_get_stream - Default output streams for logging levels + * @level: Log level + * + * By default, urgent messages are sent to "stderr". + * Other messages are sent to "stdout". + * + * Returns: "string" Prefix to be used + */ +static FILE * ntfs_log_get_stream(u32 level) +{ + FILE *stream; + + switch (level) { + case NTFS_LOG_LEVEL_INFO: + case NTFS_LOG_LEVEL_QUIET: + case NTFS_LOG_LEVEL_PROGRESS: + case NTFS_LOG_LEVEL_VERBOSE: + stream = stdout; + break; + + case NTFS_LOG_LEVEL_DEBUG: + case NTFS_LOG_LEVEL_TRACE: + case NTFS_LOG_LEVEL_ENTER: + case NTFS_LOG_LEVEL_LEAVE: + case NTFS_LOG_LEVEL_WARNING: + case NTFS_LOG_LEVEL_ERROR: + case NTFS_LOG_LEVEL_CRITICAL: + case NTFS_LOG_LEVEL_PERROR: + default: + stream = stderr; + break; + } + + return stream; +} + +/** + * ntfs_log_get_prefix - Default prefixes for logging levels + * @level: Log level to be prefixed + * + * Prefixing the logging output can make it easier to parse. + * + * Returns: "string" Prefix to be used + */ +static const char * ntfs_log_get_prefix(u32 level) +{ + const char *prefix; + + switch (level) { + case NTFS_LOG_LEVEL_DEBUG: + prefix = "DEBUG: "; + break; + case NTFS_LOG_LEVEL_TRACE: + prefix = "TRACE: "; + break; + case NTFS_LOG_LEVEL_QUIET: + prefix = "QUIET: "; + break; + case NTFS_LOG_LEVEL_INFO: + prefix = "INFO: "; + break; + case NTFS_LOG_LEVEL_VERBOSE: + prefix = "VERBOSE: "; + break; + case NTFS_LOG_LEVEL_PROGRESS: + prefix = "PROGRESS: "; + break; + case NTFS_LOG_LEVEL_WARNING: + prefix = "WARNING: "; + break; + case NTFS_LOG_LEVEL_ERROR: + prefix = "ERROR: "; + break; + case NTFS_LOG_LEVEL_PERROR: + prefix = "ERROR: "; + break; + case NTFS_LOG_LEVEL_CRITICAL: + prefix = "CRITICAL: "; + break; + default: + prefix = ""; + break; + } + + return prefix; +} + + +/** + * ntfs_log_set_handler - Provide an alternate logging handler + * @handler: function to perform the logging + * + * This alternate handler will be called for all future logging requests. + * If no @handler is specified, logging will revert to the default handler. + */ +void ntfs_log_set_handler(ntfs_log_handler *handler) +{ + if (handler) { + ntfs_log.handler = handler; +#ifdef HAVE_SYSLOG_H + if (handler == ntfs_log_handler_syslog) + openlog("ntfs-3g", LOG_PID, LOG_USER); +#endif + } else + ntfs_log.handler = ntfs_log_handler_null; +} + +/** + * ntfs_log_redirect - Pass on the request to the real handler + * @function: Function in which the log line occurred + * @file: File in which the log line occurred + * @line: Line number on which the log line occurred + * @level: Level at which the line is logged + * @data: User specified data, possibly specific to a handler + * @format: printf-style formatting string + * @...: Arguments to be formatted + * + * This is just a redirector function. The arguments are simply passed to the + * main logging handler (as defined in the global logging struct @ntfs_log). + * + * Returns: -1 Error occurred + * 0 Message wasn't logged + * num Number of output characters + */ +int ntfs_log_redirect(const char *function, const char *file, + int line, u32 level, void *data, const char *format, ...) +{ + int olderr = errno; + int ret; + va_list args; + + if (!(ntfs_log.levels & level)) /* Don't log this message */ + return 0; + + va_start(args, format); + errno = olderr; + ret = ntfs_log.handler(function, file, line, level, data, format, args); + va_end(args); + + errno = olderr; + return ret; +} + + +/** + * ntfs_log_handler_syslog - syslog logging handler + * @function: Function in which the log line occurred + * @file: File in which the log line occurred + * @line: Line number on which the log line occurred + * @level: Level at which the line is logged + * @data: User specified data, possibly specific to a handler + * @format: printf-style formatting string + * @args: Arguments to be formatted + * + * A simple syslog logging handler. Ignores colors. + * + * Returns: -1 Error occurred + * 0 Message wasn't logged + * num Number of output characters + */ + + +#ifdef HAVE_SYSLOG_H + +#define LOG_LINE_LEN 512 + +int ntfs_log_handler_syslog(const char *function __attribute__((unused)), + const char *file __attribute__((unused)), + int line __attribute__((unused)), u32 level, + void *data __attribute__((unused)), + const char *format, va_list args) +{ + char logbuf[LOG_LINE_LEN]; + int ret, olderr = errno; + +#ifndef DEBUG + if ((level & NTFS_LOG_LEVEL_PERROR) && errno == ENOSPC) + return 1; +#endif + ret = vsnprintf(logbuf, LOG_LINE_LEN, format, args); + if (ret < 0) { + vsyslog(LOG_NOTICE, format, args); + ret = 1; + goto out; + } + + if ((LOG_LINE_LEN > ret + 3) && (level & NTFS_LOG_LEVEL_PERROR)) { + strncat(logbuf, ": ", LOG_LINE_LEN - ret - 1); + strncat(logbuf, strerror(olderr), LOG_LINE_LEN - (ret + 3)); + ret = strlen(logbuf); + } + + syslog(LOG_NOTICE, "%s", logbuf); +out: + errno = olderr; + return ret; +} +#endif + +/** + * ntfs_log_handler_fprintf - Basic logging handler + * @function: Function in which the log line occurred + * @file: File in which the log line occurred + * @line: Line number on which the log line occurred + * @level: Level at which the line is logged + * @data: User specified data, possibly specific to a handler + * @format: printf-style formatting string + * @args: Arguments to be formatted + * + * A simple logging handler. This is where the log line is finally displayed. + * It is more likely that you will want to set the handler to either + * ntfs_log_handler_outerr or ntfs_log_handler_stderr. + * + * Note: For this handler, @data is a pointer to a FILE output stream. + * If @data is NULL, nothing will be displayed. + * + * Returns: -1 Error occurred + * 0 Message wasn't logged + * num Number of output characters + */ +int ntfs_log_handler_fprintf(const char *function, const char *file, + int line, u32 level, void *data, const char *format, va_list args) +{ +#ifdef DEBUG + int i; +#endif + int ret = 0; + int olderr = errno; + FILE *stream; + + if (!data) /* Interpret data as a FILE stream. */ + return 0; /* If it's NULL, we can't do anything. */ + stream = (FILE*)data; + +#ifdef DEBUG + if (level == NTFS_LOG_LEVEL_LEAVE) { + if (tab) + tab--; + return 0; + } + + for (i = 0; i < tab; i++) + ret += fprintf(stream, " "); +#endif + if ((ntfs_log.flags & NTFS_LOG_FLAG_ONLYNAME) && + (strchr(file, PATH_SEP))) /* Abbreviate the filename */ + file = strrchr(file, PATH_SEP) + 1; + + if (ntfs_log.flags & NTFS_LOG_FLAG_PREFIX) /* Prefix the output */ + ret += fprintf(stream, "%s", ntfs_log_get_prefix(level)); + + if (ntfs_log.flags & NTFS_LOG_FLAG_FILENAME) /* Source filename */ + ret += fprintf(stream, "%s ", file); + + if (ntfs_log.flags & NTFS_LOG_FLAG_LINE) /* Source line number */ + ret += fprintf(stream, "(%d) ", line); + + if ((ntfs_log.flags & NTFS_LOG_FLAG_FUNCTION) || /* Source function */ + (level & NTFS_LOG_LEVEL_TRACE) || (level & NTFS_LOG_LEVEL_ENTER)) + ret += fprintf(stream, "%s(): ", function); + + ret += vfprintf(stream, format, args); + + if (level & NTFS_LOG_LEVEL_PERROR) + ret += fprintf(stream, ": %s\n", strerror(olderr)); + +#ifdef DEBUG + if (level == NTFS_LOG_LEVEL_ENTER) + tab++; +#endif + fflush(stream); + errno = olderr; + return ret; +} + +/** + * ntfs_log_handler_null - Null logging handler (no output) + * @function: Function in which the log line occurred + * @file: File in which the log line occurred + * @line: Line number on which the log line occurred + * @level: Level at which the line is logged + * @data: User specified data, possibly specific to a handler + * @format: printf-style formatting string + * @args: Arguments to be formatted + * + * This handler produces no output. It provides a way to temporarily disable + * logging, without having to change the levels and flags. + * + * Returns: 0 Message wasn't logged + */ +int ntfs_log_handler_null(const char *function __attribute__((unused)), const char *file __attribute__((unused)), + int line __attribute__((unused)), u32 level __attribute__((unused)), void *data __attribute__((unused)), + const char *format __attribute__((unused)), va_list args __attribute__((unused))) +{ + return 0; +} + +/** + * ntfs_log_handler_stdout - All logs go to stdout + * @function: Function in which the log line occurred + * @file: File in which the log line occurred + * @line: Line number on which the log line occurred + * @level: Level at which the line is logged + * @data: User specified data, possibly specific to a handler + * @format: printf-style formatting string + * @args: Arguments to be formatted + * + * Display a log message to stdout. + * + * Note: For this handler, @data is a pointer to a FILE output stream. + * If @data is NULL, then stdout will be used. + * + * Note: This function calls ntfs_log_handler_fprintf to do the main work. + * + * Returns: -1 Error occurred + * 0 Message wasn't logged + * num Number of output characters + */ +int ntfs_log_handler_stdout(const char *function, const char *file, + int line, u32 level, void *data, const char *format, va_list args) +{ + if (!data) + data = stdout; + + return ntfs_log_handler_fprintf(function, file, line, level, data, format, args); +} + +/** + * ntfs_log_handler_outerr - Logs go to stdout/stderr depending on level + * @function: Function in which the log line occurred + * @file: File in which the log line occurred + * @line: Line number on which the log line occurred + * @level: Level at which the line is logged + * @data: User specified data, possibly specific to a handler + * @format: printf-style formatting string + * @args: Arguments to be formatted + * + * Display a log message. The output stream will be determined by the log + * level. + * + * Note: For this handler, @data is a pointer to a FILE output stream. + * If @data is NULL, the function ntfs_log_get_stream will be called + * + * Note: This function calls ntfs_log_handler_fprintf to do the main work. + * + * Returns: -1 Error occurred + * 0 Message wasn't logged + * num Number of output characters + */ +int ntfs_log_handler_outerr(const char *function, const char *file, + int line, u32 level, void *data, const char *format, va_list args) +{ + if (!data) + data = ntfs_log_get_stream(level); + + return ntfs_log_handler_fprintf(function, file, line, level, data, format, args); +} + +/** + * ntfs_log_handler_stderr - All logs go to stderr + * @function: Function in which the log line occurred + * @file: File in which the log line occurred + * @line: Line number on which the log line occurred + * @level: Level at which the line is logged + * @data: User specified data, possibly specific to a handler + * @format: printf-style formatting string + * @args: Arguments to be formatted + * + * Display a log message to stderr. + * + * Note: For this handler, @data is a pointer to a FILE output stream. + * If @data is NULL, then stdout will be used. + * + * Note: This function calls ntfs_log_handler_fprintf to do the main work. + * + * Returns: -1 Error occurred + * 0 Message wasn't logged + * num Number of output characters + */ +int ntfs_log_handler_stderr(const char *function, const char *file, + int line, u32 level, void *data, const char *format, va_list args) +{ + if (!data) + data = stderr; + + return ntfs_log_handler_fprintf(function, file, line, level, data, format, args); +} + + +/** + * ntfs_log_parse_option - Act upon command line options + * @option: Option flag + * + * Delegate some of the work of parsing the command line. All the options begin + * with "--log-". Options cause log levels to be enabled in @ntfs_log (the + * global logging structure). + * + * Note: The "colour" option changes the logging handler. + * + * Returns: TRUE Option understood + * FALSE Invalid log option + */ +BOOL ntfs_log_parse_option(const char *option) +{ + if (strcmp(option, "--log-debug") == 0) { + ntfs_log_set_levels(NTFS_LOG_LEVEL_DEBUG); + return TRUE; + } else if (strcmp(option, "--log-verbose") == 0) { + ntfs_log_set_levels(NTFS_LOG_LEVEL_VERBOSE); + return TRUE; + } else if (strcmp(option, "--log-quiet") == 0) { + ntfs_log_clear_levels(NTFS_LOG_LEVEL_QUIET); + return TRUE; + } else if (strcmp(option, "--log-trace") == 0) { + ntfs_log_set_levels(NTFS_LOG_LEVEL_TRACE); + return TRUE; + } + + ntfs_log_debug("Unknown logging option '%s'\n", option); + return FALSE; +} + diff --git a/libntfs-3g/mft.c b/libntfs-3g/mft.c new file mode 100755 index 0000000..e93c664 --- a/dev/null +++ b/libntfs-3g/mft.c @@ -0,0 +1,1909 @@ +/** + * mft.c - Mft record handling code. Originated from the Linux-NTFS project. + * + * Copyright (c) 2000-2004 Anton Altaparmakov + * Copyright (c) 2004-2005 Richard Russon + * Copyright (c) 2004-2008 Szabolcs Szakacsits + * Copyright (c) 2005 Yura Pakhuchiy + * + * This program/include file 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/include file 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 (in the main directory of the NTFS-3G + * distribution in the file COPYING); if not, write to the Free Software + * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STDIO_H +#include +#endif +#ifdef HAVE_ERRNO_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_LIMITS_H +#include +#endif +#include + +#include "compat.h" +#include "types.h" +#include "device.h" +#include "debug.h" +#include "bitmap.h" +#include "attrib.h" +#include "inode.h" +#include "volume.h" +#include "layout.h" +#include "lcnalloc.h" +#include "mft.h" +#include "logging.h" +#include "misc.h" + +/** + * ntfs_mft_records_read - read records from the mft from disk + * @vol: volume to read from + * @mref: starting mft record number to read + * @count: number of mft records to read + * @b: output data buffer + * + * Read @count mft records starting at @mref from volume @vol into buffer + * @b. Return 0 on success or -1 on error, with errno set to the error + * code. + * + * If any of the records exceed the initialized size of the $MFT/$DATA + * attribute, i.e. they cannot possibly be allocated mft records, assume this + * is a bug and return error code ESPIPE. + * + * The read mft records are mst deprotected and are hence ready to use. The + * caller should check each record with is_baad_record() in case mst + * deprotection failed. + * + * NOTE: @b has to be at least of size @count * vol->mft_record_size. + */ +int ntfs_mft_records_read(const ntfs_volume *vol, const MFT_REF mref, + const s64 count, MFT_RECORD *b) +{ + s64 br; + VCN m; + + ntfs_log_trace("inode %llu\n", (unsigned long long)MREF(mref)); + + if (!vol || !vol->mft_na || !b || count < 0) { + errno = EINVAL; + ntfs_log_perror("%s: b=%p count=%lld mft=%llu", __FUNCTION__, + b, (long long)count, (unsigned long long)MREF(mref)); + return -1; + } + m = MREF(mref); + /* Refuse to read non-allocated mft records. */ + if (m + count > vol->mft_na->initialized_size >> + vol->mft_record_size_bits) { + errno = ESPIPE; + ntfs_log_perror("Trying to read non-allocated mft records " + "(%lld > %lld)", (long long)m + count, + (long long)vol->mft_na->initialized_size >> + vol->mft_record_size_bits); + return -1; + } + br = ntfs_attr_mst_pread(vol->mft_na, m << vol->mft_record_size_bits, + count, vol->mft_record_size, b); + if (br != count) { + if (br != -1) + errno = EIO; + ntfs_log_perror("Failed to read of MFT, mft=%llu count=%lld " + "br=%lld", (long long)m, (long long)count, + (long long)br); + return -1; + } + return 0; +} + +/** + * ntfs_mft_records_write - write mft records to disk + * @vol: volume to write to + * @mref: starting mft record number to write + * @count: number of mft records to write + * @b: data buffer containing the mft records to write + * + * Write @count mft records starting at @mref from data buffer @b to volume + * @vol. Return 0 on success or -1 on error, with errno set to the error code. + * + * If any of the records exceed the initialized size of the $MFT/$DATA + * attribute, i.e. they cannot possibly be allocated mft records, assume this + * is a bug and return error code ESPIPE. + * + * Before the mft records are written, they are mst protected. After the write, + * they are deprotected again, thus resulting in an increase in the update + * sequence number inside the data buffer @b. + * + * If any mft records are written which are also represented in the mft mirror + * $MFTMirr, we make a copy of the relevant parts of the data buffer @b into a + * temporary buffer before we do the actual write. Then if at least one mft + * record was successfully written, we write the appropriate mft records from + * the copied buffer to the mft mirror, too. + */ +int ntfs_mft_records_write(const ntfs_volume *vol, const MFT_REF mref, + const s64 count, MFT_RECORD *b) +{ + s64 bw; + VCN m; + void *bmirr = NULL; + int cnt = 0, res = 0; + + if (!vol || !vol->mft_na || vol->mftmirr_size <= 0 || !b || count < 0) { + errno = EINVAL; + return -1; + } + m = MREF(mref); + /* Refuse to write non-allocated mft records. */ + if (m + count > vol->mft_na->initialized_size >> + vol->mft_record_size_bits) { + errno = ESPIPE; + ntfs_log_perror("Trying to write non-allocated mft records " + "(%lld > %lld)", (long long)m + count, + (long long)vol->mft_na->initialized_size >> + vol->mft_record_size_bits); + return -1; + } + if (m < vol->mftmirr_size) { + if (!vol->mftmirr_na) { + errno = EINVAL; + return -1; + } + cnt = vol->mftmirr_size - m; + if (cnt > count) + cnt = count; + bmirr = ntfs_malloc(cnt * vol->mft_record_size); + if (!bmirr) + return -1; + memcpy(bmirr, b, cnt * vol->mft_record_size); + } + bw = ntfs_attr_mst_pwrite(vol->mft_na, m << vol->mft_record_size_bits, + count, vol->mft_record_size, b); + if (bw != count) { + if (bw != -1) + errno = EIO; + if (bw >= 0) + ntfs_log_debug("Error: partial write while writing $Mft " + "record(s)!\n"); + else + ntfs_log_perror("Error writing $Mft record(s)"); + res = errno; + } + if (bmirr && bw > 0) { + if (bw < cnt) + cnt = bw; + bw = ntfs_attr_mst_pwrite(vol->mftmirr_na, + m << vol->mft_record_size_bits, cnt, + vol->mft_record_size, bmirr); + if (bw != cnt) { + if (bw != -1) + errno = EIO; + ntfs_log_debug("Error: failed to sync $MFTMirr! Run " + "chkdsk.\n"); + res = errno; + } + } + free(bmirr); + if (!res) + return res; + errno = res; + return -1; +} + +int ntfs_mft_record_check(const ntfs_volume *vol, const MFT_REF mref, + MFT_RECORD *m) +{ + ATTR_RECORD *a; + int ret = -1; + + if (!ntfs_is_file_record(m->magic)) { + ntfs_log_error("Record %llu has no FILE magic (0x%x)\n", + (unsigned long long)MREF(mref), *(le32 *)m); + goto err_out; + } + + if (le32_to_cpu(m->bytes_allocated) != vol->mft_record_size) { + ntfs_log_error("Record %llu has corrupt allocation size " + "(%u <> %u)\n", (unsigned long long)MREF(mref), + vol->mft_record_size, + le32_to_cpu(m->bytes_allocated)); + goto err_out; + } + + a = (ATTR_RECORD *)((char *)m + le16_to_cpu(m->attrs_offset)); + if (p2n(a) < p2n(m) || (char *)a > (char *)m + vol->mft_record_size) { + ntfs_log_error("Record %llu is corrupt\n", + (unsigned long long)MREF(mref)); + goto err_out; + } + + ret = 0; +err_out: + if (ret) + errno = EIO; + return ret; +} + +/** + * ntfs_file_record_read - read a FILE record from the mft from disk + * @vol: volume to read from + * @mref: mft reference specifying mft record to read + * @mrec: address of pointer in which to return the mft record + * @attr: address of pointer in which to return the first attribute + * + * Read a FILE record from the mft of @vol from the storage medium. @mref + * specifies the mft record to read, including the sequence number, which can + * be 0 if no sequence number checking is to be performed. + * + * The function allocates a buffer large enough to hold the mft record and + * reads the record into the buffer (mst deprotecting it in the process). + * *@mrec is then set to point to the buffer. + * + * If @attr is not NULL, *@attr is set to point to the first attribute in the + * mft record, i.e. *@attr is a pointer into *@mrec. + * + * Return 0 on success, or -1 on error, with errno set to the error code. + * + * The read mft record is checked for having the magic FILE, + * and for having a matching sequence number (if MSEQNO(*@mref) != 0). + * If either of these fails, -1 is returned and errno is set to EIO. If you get + * this, but you still want to read the mft record (e.g. in order to correct + * it), use ntfs_mft_record_read() directly. + * + * Note: Caller has to free *@mrec when finished. + * + * Note: We do not check if the mft record is flagged in use. The caller can + * check if desired. + */ +int ntfs_file_record_read(const ntfs_volume *vol, const MFT_REF mref, + MFT_RECORD **mrec, ATTR_RECORD **attr) +{ + MFT_RECORD *m; + + if (!vol || !mrec) { + errno = EINVAL; + ntfs_log_perror("%s: mrec=%p", __FUNCTION__, mrec); + return -1; + } + + m = *mrec; + if (!m) { + m = ntfs_malloc(vol->mft_record_size); + if (!m) + return -1; + } + if (ntfs_mft_record_read(vol, mref, m)) + goto err_out; + + if (ntfs_mft_record_check(vol, mref, m)) + goto err_out; + + if (MSEQNO(mref) && MSEQNO(mref) != le16_to_cpu(m->sequence_number)) { + ntfs_log_error("Record %llu has wrong SeqNo (%d <> %d)\n", + (unsigned long long)MREF(mref), MSEQNO(mref), + le16_to_cpu(m->sequence_number)); + errno = EIO; + goto err_out; + } + *mrec = m; + if (attr) + *attr = (ATTR_RECORD*)((char*)m + le16_to_cpu(m->attrs_offset)); + return 0; +err_out: + if (m != *mrec) + free(m); + return -1; +} + +/** + * ntfs_mft_record_layout - layout an mft record into a memory buffer + * @vol: volume to which the mft record will belong + * @mref: mft reference specifying the mft record number + * @mrec: destination buffer of size >= @vol->mft_record_size bytes + * + * Layout an empty, unused mft record with the mft reference @mref into the + * buffer @m. The volume @vol is needed because the mft record structure was + * modified in NTFS 3.1 so we need to know which volume version this mft record + * will be used on. + * + * On success return 0 and on error return -1 with errno set to the error code. + */ +int ntfs_mft_record_layout(const ntfs_volume *vol, const MFT_REF mref, + MFT_RECORD *mrec) +{ + ATTR_RECORD *a; + + if (!vol || !mrec) { + errno = EINVAL; + ntfs_log_perror("%s: mrec=%p", __FUNCTION__, mrec); + return -1; + } + /* Aligned to 2-byte boundary. */ + if (vol->major_ver < 3 || (vol->major_ver == 3 && !vol->minor_ver)) + mrec->usa_ofs = cpu_to_le16((sizeof(MFT_RECORD_OLD) + 1) & ~1); + else { + /* Abort if mref is > 32 bits. */ + if (MREF(mref) & 0x0000ffff00000000ull) { + errno = ERANGE; + ntfs_log_perror("Mft reference exceeds 32 bits"); + return -1; + } + mrec->usa_ofs = cpu_to_le16((sizeof(MFT_RECORD) + 1) & ~1); + /* + * Set the NTFS 3.1+ specific fields while we know that the + * volume version is 3.1+. + */ + mrec->reserved = cpu_to_le16(0); + mrec->mft_record_number = cpu_to_le32(MREF(mref)); + } + mrec->magic = magic_FILE; + if (vol->mft_record_size >= NTFS_BLOCK_SIZE) + mrec->usa_count = cpu_to_le16(vol->mft_record_size / + NTFS_BLOCK_SIZE + 1); + else { + mrec->usa_count = cpu_to_le16(1); + ntfs_log_error("Sector size is bigger than MFT record size. " + "Setting usa_count to 1. If Windows chkdsk " + "reports this as corruption, please email %s " + "stating that you saw this message and that " + "the file system created was corrupt. " + "Thank you.\n", NTFS_DEV_LIST); + } + /* Set the update sequence number to 1. */ + *(u16*)((u8*)mrec + le16_to_cpu(mrec->usa_ofs)) = cpu_to_le16(1); + mrec->lsn = cpu_to_le64(0ull); + mrec->sequence_number = cpu_to_le16(1); + mrec->link_count = cpu_to_le16(0); + /* Aligned to 8-byte boundary. */ + mrec->attrs_offset = cpu_to_le16((le16_to_cpu(mrec->usa_ofs) + + (le16_to_cpu(mrec->usa_count) << 1) + 7) & ~7); + mrec->flags = cpu_to_le16(0); + /* + * Using attrs_offset plus eight bytes (for the termination attribute), + * aligned to 8-byte boundary. + */ + mrec->bytes_in_use = cpu_to_le32((le16_to_cpu(mrec->attrs_offset) + 8 + + 7) & ~7); + mrec->bytes_allocated = cpu_to_le32(vol->mft_record_size); + mrec->base_mft_record = cpu_to_le64((MFT_REF)0); + mrec->next_attr_instance = cpu_to_le16(0); + a = (ATTR_RECORD*)((u8*)mrec + le16_to_cpu(mrec->attrs_offset)); + a->type = AT_END; + a->length = cpu_to_le32(0); + /* Finally, clear the unused part of the mft record. */ + memset((u8*)a + 8, 0, vol->mft_record_size - ((u8*)a + 8 - (u8*)mrec)); + return 0; +} + +/** + * ntfs_mft_record_format - format an mft record on an ntfs volume + * @vol: volume on which to format the mft record + * @mref: mft reference specifying mft record to format + * + * Format the mft record with the mft reference @mref in $MFT/$DATA, i.e. lay + * out an empty, unused mft record in memory and write it to the volume @vol. + * + * On success return 0 and on error return -1 with errno set to the error code. + */ +int ntfs_mft_record_format(const ntfs_volume *vol, const MFT_REF mref) +{ + MFT_RECORD *m; + int ret = -1; + + ntfs_log_enter("Entering\n"); + + m = ntfs_calloc(vol->mft_record_size); + if (!m) + goto out; + + if (ntfs_mft_record_layout(vol, mref, m)) + goto free_m; + + if (ntfs_mft_record_write(vol, mref, m)) + goto free_m; + + ret = 0; +free_m: + free(m); +out: + ntfs_log_leave("\n"); + return ret; +} + +static const char *es = " Leaving inconsistent metadata. Run chkdsk."; + +/** + * ntfs_ffz - Find the first unset (zero) bit in a word + * @word: + * + * Description... + * + * Returns: + */ +static inline unsigned int ntfs_ffz(unsigned int word) +{ + return ffs(~word) - 1; +} + +static int ntfs_is_mft(ntfs_inode *ni) +{ + if (ni && ni->mft_no == FILE_MFT) + return 1; + return 0; +} + +#ifndef PAGE_SIZE +#define PAGE_SIZE 4096 +#endif + +#define RESERVED_MFT_RECORDS 64 + +/** + * ntfs_mft_bitmap_find_free_rec - find a free mft record in the mft bitmap + * @vol: volume on which to search for a free mft record + * @base_ni: open base inode if allocating an extent mft record or NULL + * + * Search for a free mft record in the mft bitmap attribute on the ntfs volume + * @vol. + * + * If @base_ni is NULL start the search at the default allocator position. + * + * If @base_ni is not NULL start the search at the mft record after the base + * mft record @base_ni. + * + * Return the free mft record on success and -1 on error with errno set to the + * error code. An error code of ENOSPC means that there are no free mft + * records in the currently initialized mft bitmap. + */ +static int ntfs_mft_bitmap_find_free_rec(ntfs_volume *vol, ntfs_inode *base_ni) +{ + s64 pass_end, ll, data_pos, pass_start, ofs, bit; + ntfs_attr *mftbmp_na; + u8 *buf, *byte; + unsigned int size; + u8 pass, b; + int ret = -1; + + ntfs_log_enter("Entering\n"); + + mftbmp_na = vol->mftbmp_na; + /* + * Set the end of the pass making sure we do not overflow the mft + * bitmap. + */ + size = PAGE_SIZE; + pass_end = vol->mft_na->allocated_size >> vol->mft_record_size_bits; + ll = mftbmp_na->initialized_size << 3; + if (pass_end > ll) + pass_end = ll; + pass = 1; + if (!base_ni) + data_pos = vol->mft_data_pos; + else + data_pos = base_ni->mft_no + 1; + if (data_pos < RESERVED_MFT_RECORDS) + data_pos = RESERVED_MFT_RECORDS; + if (data_pos >= pass_end) { + data_pos = RESERVED_MFT_RECORDS; + pass = 2; + /* This happens on a freshly formatted volume. */ + if (data_pos >= pass_end) { + errno = ENOSPC; + goto leave; + } + } + if (ntfs_is_mft(base_ni)) { + data_pos = 0; + pass = 2; + } + pass_start = data_pos; + buf = ntfs_malloc(PAGE_SIZE); + if (!buf) + goto leave; + + ntfs_log_debug("Starting bitmap search: pass %u, pass_start 0x%llx, " + "pass_end 0x%llx, data_pos 0x%llx.\n", pass, + (long long)pass_start, (long long)pass_end, + (long long)data_pos); +#ifdef DEBUG + byte = NULL; + b = 0; +#endif + /* Loop until a free mft record is found. */ + for (; pass <= 2; size = PAGE_SIZE) { + /* Cap size to pass_end. */ + ofs = data_pos >> 3; + ll = ((pass_end + 7) >> 3) - ofs; + if (size > ll) + size = ll; + ll = ntfs_attr_pread(mftbmp_na, ofs, size, buf); + if (ll < 0) { + ntfs_log_perror("Failed to read $MFT bitmap"); + free(buf); + goto leave; + } + ntfs_log_debug("Read 0x%llx bytes.\n", (long long)ll); + /* If we read at least one byte, search @buf for a zero bit. */ + if (ll) { + size = ll << 3; + bit = data_pos & 7; + data_pos &= ~7ull; + ntfs_log_debug("Before inner for loop: size 0x%x, " + "data_pos 0x%llx, bit 0x%llx, " + "*byte 0x%hhx, b %u.\n", size, + (long long)data_pos, (long long)bit, + byte ? *byte : -1, b); + for (; bit < size && data_pos + bit < pass_end; + bit &= ~7ull, bit += 8) { + /* + * If we're extending $MFT and running out of the first + * mft record (base record) then give up searching since + * no guarantee that the found record will be accessible. + */ + if (ntfs_is_mft(base_ni) && bit > 400) + goto out; + + byte = buf + (bit >> 3); + if (*byte == 0xff) + continue; + + /* Note: ffz() result must be zero based. */ + b = ntfs_ffz((unsigned long)*byte); + if (b < 8 && b >= (bit & 7)) { + free(buf); + ret = data_pos + (bit & ~7ull) + b; + goto leave; + } + } + ntfs_log_debug("After inner for loop: size 0x%x, " + "data_pos 0x%llx, bit 0x%llx, " + "*byte 0x%hhx, b %u.\n", size, + (long long)data_pos, (long long)bit, + byte ? *byte : -1, b); + data_pos += size; + /* + * If the end of the pass has not been reached yet, + * continue searching the mft bitmap for a zero bit. + */ + if (data_pos < pass_end) + continue; + } + /* Do the next pass. */ + pass++; + if (pass == 2) { + /* + * Starting the second pass, in which we scan the first + * part of the zone which we omitted earlier. + */ + pass_end = pass_start; + data_pos = pass_start = RESERVED_MFT_RECORDS; + ntfs_log_debug("pass %i, pass_start 0x%llx, pass_end " + "0x%llx.\n", pass, (long long)pass_start, + (long long)pass_end); + if (data_pos >= pass_end) + break; + } + } + /* No free mft records in currently initialized mft bitmap. */ +out: + free(buf); + errno = ENOSPC; +leave: + ntfs_log_leave("\n"); + return ret; +} + +static int ntfs_mft_attr_extend(ntfs_attr *na) +{ + int ret = STATUS_ERROR; + ntfs_log_enter("Entering\n"); + + if (!NInoAttrList(na->ni)) { + if (ntfs_inode_add_attrlist(na->ni)) { + ntfs_log_perror("%s: Can not add attrlist #3", __FUNCTION__); + goto out; + } + /* We can't sync the $MFT inode since its runlist is bogus. */ + ret = STATUS_KEEP_SEARCHING; + goto out; + } + + if (ntfs_attr_update_mapping_pairs(na, 0)) { + ntfs_log_perror("%s: MP update failed", __FUNCTION__); + goto out; + } + + ret = STATUS_OK; +out: + ntfs_log_leave("\n"); + return ret; +} + +/** + * ntfs_mft_bitmap_extend_allocation_i - see ntfs_mft_bitmap_extend_allocation + */ +static int ntfs_mft_bitmap_extend_allocation_i(ntfs_volume *vol) +{ + LCN lcn; + s64 ll = 0; /* silence compiler warning */ + ntfs_attr *mftbmp_na; + runlist_element *rl, *rl2 = NULL; /* silence compiler warning */ + ntfs_attr_search_ctx *ctx; + MFT_RECORD *m = NULL; /* silence compiler warning */ + ATTR_RECORD *a = NULL; /* silence compiler warning */ + int err, mp_size; + int ret = STATUS_ERROR; + u32 old_alen = 0; /* silence compiler warning */ + BOOL mp_rebuilt = FALSE; + BOOL update_mp = FALSE; + + mftbmp_na = vol->mftbmp_na; + /* + * Determine the last lcn of the mft bitmap. The allocated size of the + * mft bitmap cannot be zero so we are ok to do this. + */ + rl = ntfs_attr_find_vcn(mftbmp_na, (mftbmp_na->allocated_size - 1) >> + vol->cluster_size_bits); + if (!rl || !rl->length || rl->lcn < 0) { + ntfs_log_error("Failed to determine last allocated " + "cluster of mft bitmap attribute.\n"); + if (rl) + errno = EIO; + return STATUS_ERROR; + } + lcn = rl->lcn + rl->length; + + rl2 = ntfs_cluster_alloc(vol, rl[1].vcn, 1, lcn, DATA_ZONE); + if (!rl2) { + ntfs_log_error("Failed to allocate a cluster for " + "the mft bitmap.\n"); + return STATUS_ERROR; + } + rl = ntfs_runlists_merge(mftbmp_na->rl, rl2); + if (!rl) { + err = errno; + ntfs_log_error("Failed to merge runlists for mft " + "bitmap.\n"); + if (ntfs_cluster_free_from_rl(vol, rl2)) + ntfs_log_error("Failed to deallocate " + "cluster.%s\n", es); + free(rl2); + errno = err; + return STATUS_ERROR; + } + mftbmp_na->rl = rl; + ntfs_log_debug("Adding one run to mft bitmap.\n"); + /* Find the last run in the new runlist. */ + for (; rl[1].length; rl++) + ; + /* + * Update the attribute record as well. Note: @rl is the last + * (non-terminator) runlist element of mft bitmap. + */ + ctx = ntfs_attr_get_search_ctx(mftbmp_na->ni, NULL); + if (!ctx) + goto undo_alloc; + + if (ntfs_attr_lookup(mftbmp_na->type, mftbmp_na->name, + mftbmp_na->name_len, 0, rl[1].vcn, NULL, 0, ctx)) { + ntfs_log_error("Failed to find last attribute extent of " + "mft bitmap attribute.\n"); + goto undo_alloc; + } + m = ctx->mrec; + a = ctx->attr; + ll = sle64_to_cpu(a->lowest_vcn); + rl2 = ntfs_attr_find_vcn(mftbmp_na, ll); + if (!rl2 || !rl2->length) { + ntfs_log_error("Failed to determine previous last " + "allocated cluster of mft bitmap attribute.\n"); + if (rl2) + errno = EIO; + goto undo_alloc; + } + /* Get the size for the new mapping pairs array for this extent. */ + mp_size = ntfs_get_size_for_mapping_pairs(vol, rl2, ll, INT_MAX); + if (mp_size <= 0) { + ntfs_log_error("Get size for mapping pairs failed for " + "mft bitmap attribute extent.\n"); + goto undo_alloc; + } + /* Expand the attribute record if necessary. */ + old_alen = le32_to_cpu(a->length); + if (ntfs_attr_record_resize(m, a, mp_size + + le16_to_cpu(a->mapping_pairs_offset))) { + ntfs_log_info("extending $MFT bitmap\n"); + ret = ntfs_mft_attr_extend(vol->mftbmp_na); + if (ret == STATUS_OK) + goto ok; + if (ret == STATUS_ERROR) { + ntfs_log_perror("%s: ntfs_mft_attr_extend failed", __FUNCTION__); + update_mp = TRUE; + } + goto undo_alloc; + } + mp_rebuilt = TRUE; + /* Generate the mapping pairs array directly into the attr record. */ + if (ntfs_mapping_pairs_build(vol, (u8*)a + + le16_to_cpu(a->mapping_pairs_offset), mp_size, rl2, ll, + NULL)) { + ntfs_log_error("Failed to build mapping pairs array for " + "mft bitmap attribute.\n"); + errno = EIO; + goto undo_alloc; + } + /* Update the highest_vcn. */ + a->highest_vcn = cpu_to_sle64(rl[1].vcn - 1); + /* + * We now have extended the mft bitmap allocated_size by one cluster. + * Reflect this in the ntfs_attr structure and the attribute record. + */ + if (a->lowest_vcn) { + /* + * We are not in the first attribute extent, switch to it, but + * first ensure the changes will make it to disk later. + */ + ntfs_inode_mark_dirty(ctx->ntfs_ino); + ntfs_attr_reinit_search_ctx(ctx); + if (ntfs_attr_lookup(mftbmp_na->type, mftbmp_na->name, + mftbmp_na->name_len, 0, 0, NULL, 0, ctx)) { + ntfs_log_error("Failed to find first attribute " + "extent of mft bitmap attribute.\n"); + goto restore_undo_alloc; + } + a = ctx->attr; + } +ok: + mftbmp_na->allocated_size += vol->cluster_size; + a->allocated_size = cpu_to_sle64(mftbmp_na->allocated_size); + /* Ensure the changes make it to disk. */ + ntfs_inode_mark_dirty(ctx->ntfs_ino); + ntfs_attr_put_search_ctx(ctx); + return STATUS_OK; + +restore_undo_alloc: + err = errno; + ntfs_attr_reinit_search_ctx(ctx); + if (ntfs_attr_lookup(mftbmp_na->type, mftbmp_na->name, + mftbmp_na->name_len, 0, rl[1].vcn, NULL, 0, ctx)) { + ntfs_log_error("Failed to find last attribute extent of " + "mft bitmap attribute.%s\n", es); + ntfs_attr_put_search_ctx(ctx); + mftbmp_na->allocated_size += vol->cluster_size; + /* + * The only thing that is now wrong is ->allocated_size of the + * base attribute extent which chkdsk should be able to fix. + */ + errno = err; + return STATUS_ERROR; + } + m = ctx->mrec; + a = ctx->attr; + a->highest_vcn = cpu_to_sle64(rl[1].vcn - 2); + errno = err; +undo_alloc: + err = errno; + + /* Remove the last run from the runlist. */ + lcn = rl->lcn; + rl->lcn = rl[1].lcn; + rl->length = 0; + + /* FIXME: use an ntfs_cluster_free_* function */ + if (ntfs_bitmap_clear_bit(vol->lcnbmp_na, lcn)) + ntfs_log_error("Failed to free cluster.%s\n", es); + else + vol->free_clusters++; + if (mp_rebuilt) { + if (ntfs_mapping_pairs_build(vol, (u8*)a + + le16_to_cpu(a->mapping_pairs_offset), + old_alen - le16_to_cpu(a->mapping_pairs_offset), + rl2, ll, NULL)) + ntfs_log_error("Failed to restore mapping " + "pairs array.%s\n", es); + if (ntfs_attr_record_resize(m, a, old_alen)) + ntfs_log_error("Failed to restore attribute " + "record.%s\n", es); + ntfs_inode_mark_dirty(ctx->ntfs_ino); + } + if (update_mp) { + if (ntfs_attr_update_mapping_pairs(vol->mftbmp_na, 0)) + ntfs_log_perror("%s: MP update failed", __FUNCTION__); + } + if (ctx) + ntfs_attr_put_search_ctx(ctx); + errno = err; + return ret; +} + +/** + * ntfs_mft_bitmap_extend_allocation - extend mft bitmap attribute by a cluster + * @vol: volume on which to extend the mft bitmap attribute + * + * Extend the mft bitmap attribute on the ntfs volume @vol by one cluster. + * + * Note: Only changes allocated_size, i.e. does not touch initialized_size or + * data_size. + * + * Return 0 on success and -1 on error with errno set to the error code. + */ +static int ntfs_mft_bitmap_extend_allocation(ntfs_volume *vol) +{ + int ret; + + ntfs_log_enter("Entering\n"); + ret = ntfs_mft_bitmap_extend_allocation_i(vol); + ntfs_log_leave("\n"); + return ret; +} +/** + * ntfs_mft_bitmap_extend_initialized - extend mft bitmap initialized data + * @vol: volume on which to extend the mft bitmap attribute + * + * Extend the initialized portion of the mft bitmap attribute on the ntfs + * volume @vol by 8 bytes. + * + * Note: Only changes initialized_size and data_size, i.e. requires that + * allocated_size is big enough to fit the new initialized_size. + * + * Return 0 on success and -1 on error with errno set to the error code. + */ +static int ntfs_mft_bitmap_extend_initialized(ntfs_volume *vol) +{ + s64 old_data_size, old_initialized_size, ll; + ntfs_attr *mftbmp_na; + ntfs_attr_search_ctx *ctx; + ATTR_RECORD *a; + int err; + int ret = -1; + + ntfs_log_enter("Entering\n"); + + mftbmp_na = vol->mftbmp_na; + ctx = ntfs_attr_get_search_ctx(mftbmp_na->ni, NULL); + if (!ctx) + goto out; + + if (ntfs_attr_lookup(mftbmp_na->type, mftbmp_na->name, + mftbmp_na->name_len, 0, 0, NULL, 0, ctx)) { + ntfs_log_error("Failed to find first attribute extent of " + "mft bitmap attribute.\n"); + err = errno; + goto put_err_out; + } + a = ctx->attr; + old_data_size = mftbmp_na->data_size; + old_initialized_size = mftbmp_na->initialized_size; + mftbmp_na->initialized_size += 8; + a->initialized_size = cpu_to_sle64(mftbmp_na->initialized_size); + if (mftbmp_na->initialized_size > mftbmp_na->data_size) { + mftbmp_na->data_size = mftbmp_na->initialized_size; + a->data_size = cpu_to_sle64(mftbmp_na->data_size); + } + /* Ensure the changes make it to disk. */ + ntfs_inode_mark_dirty(ctx->ntfs_ino); + ntfs_attr_put_search_ctx(ctx); + /* Initialize the mft bitmap attribute value with zeroes. */ + ll = 0; + ll = ntfs_attr_pwrite(mftbmp_na, old_initialized_size, 8, &ll); + if (ll == 8) { + ntfs_log_debug("Wrote eight initialized bytes to mft bitmap.\n"); + vol->free_mft_records += (8 * 8); + ret = 0; + goto out; + } + ntfs_log_error("Failed to write to mft bitmap.\n"); + err = errno; + if (ll >= 0) + err = EIO; + /* Try to recover from the error. */ + ctx = ntfs_attr_get_search_ctx(mftbmp_na->ni, NULL); + if (!ctx) + goto err_out; + + if (ntfs_attr_lookup(mftbmp_na->type, mftbmp_na->name, + mftbmp_na->name_len, 0, 0, NULL, 0, ctx)) { + ntfs_log_error("Failed to find first attribute extent of " + "mft bitmap attribute.%s\n", es); +put_err_out: + ntfs_attr_put_search_ctx(ctx); + goto err_out; + } + a = ctx->attr; + mftbmp_na->initialized_size = old_initialized_size; + a->initialized_size = cpu_to_sle64(old_initialized_size); + if (mftbmp_na->data_size != old_data_size) { + mftbmp_na->data_size = old_data_size; + a->data_size = cpu_to_sle64(old_data_size); + } + ntfs_inode_mark_dirty(ctx->ntfs_ino); + ntfs_attr_put_search_ctx(ctx); + ntfs_log_debug("Restored status of mftbmp: allocated_size 0x%llx, " + "data_size 0x%llx, initialized_size 0x%llx.\n", + (long long)mftbmp_na->allocated_size, + (long long)mftbmp_na->data_size, + (long long)mftbmp_na->initialized_size); +err_out: + errno = err; +out: + ntfs_log_leave("\n"); + return ret; +} + +/** + * ntfs_mft_data_extend_allocation - extend mft data attribute + * @vol: volume on which to extend the mft data attribute + * + * Extend the mft data attribute on the ntfs volume @vol by 16 mft records + * worth of clusters or if not enough space for this by one mft record worth + * of clusters. + * + * Note: Only changes allocated_size, i.e. does not touch initialized_size or + * data_size. + * + * Return 0 on success and -1 on error with errno set to the error code. + */ +static int ntfs_mft_data_extend_allocation(ntfs_volume *vol) +{ + LCN lcn; + VCN old_last_vcn; + s64 min_nr, nr, ll = 0; /* silence compiler warning */ + ntfs_attr *mft_na; + runlist_element *rl, *rl2; + ntfs_attr_search_ctx *ctx; + MFT_RECORD *m = NULL; /* silence compiler warning */ + ATTR_RECORD *a = NULL; /* silence compiler warning */ + int err, mp_size; + int ret = STATUS_ERROR; + u32 old_alen = 0; /* silence compiler warning */ + BOOL mp_rebuilt = FALSE; + BOOL update_mp = FALSE; + + ntfs_log_enter("Extending mft data allocation.\n"); + + mft_na = vol->mft_na; + /* + * Determine the preferred allocation location, i.e. the last lcn of + * the mft data attribute. The allocated size of the mft data + * attribute cannot be zero so we are ok to do this. + */ + rl = ntfs_attr_find_vcn(mft_na, + (mft_na->allocated_size - 1) >> vol->cluster_size_bits); + + if (!rl || !rl->length || rl->lcn < 0) { + ntfs_log_error("Failed to determine last allocated " + "cluster of mft data attribute.\n"); + if (rl) + errno = EIO; + goto out; + } + + lcn = rl->lcn + rl->length; + ntfs_log_debug("Last lcn of mft data attribute is 0x%llx.\n", (long long)lcn); + /* Minimum allocation is one mft record worth of clusters. */ + min_nr = vol->mft_record_size >> vol->cluster_size_bits; + if (!min_nr) + min_nr = 1; + /* Want to allocate 16 mft records worth of clusters. */ + nr = vol->mft_record_size << 4 >> vol->cluster_size_bits; + if (!nr) + nr = min_nr; + + old_last_vcn = rl[1].vcn; + do { + rl2 = ntfs_cluster_alloc(vol, old_last_vcn, nr, lcn, MFT_ZONE); + if (rl2) + break; + if (errno != ENOSPC || nr == min_nr) { + ntfs_log_perror("Failed to allocate (%lld) clusters " + "for $MFT", (long long)nr); + goto out; + } + /* + * There is not enough space to do the allocation, but there + * might be enough space to do a minimal allocation so try that + * before failing. + */ + nr = min_nr; + ntfs_log_debug("Retrying mft data allocation with minimal cluster " + "count %lli.\n", (long long)nr); + } while (1); + + ntfs_log_debug("Allocated %lld clusters.\n", (long long)nr); + + rl = ntfs_runlists_merge(mft_na->rl, rl2); + if (!rl) { + err = errno; + ntfs_log_error("Failed to merge runlists for mft data " + "attribute.\n"); + if (ntfs_cluster_free_from_rl(vol, rl2)) + ntfs_log_error("Failed to deallocate clusters " + "from the mft data attribute.%s\n", es); + free(rl2); + errno = err; + goto out; + } + mft_na->rl = rl; + + /* Find the last run in the new runlist. */ + for (; rl[1].length; rl++) + ; + /* Update the attribute record as well. */ + ctx = ntfs_attr_get_search_ctx(mft_na->ni, NULL); + if (!ctx) + goto undo_alloc; + + if (ntfs_attr_lookup(mft_na->type, mft_na->name, mft_na->name_len, 0, + rl[1].vcn, NULL, 0, ctx)) { + ntfs_log_error("Failed to find last attribute extent of " + "mft data attribute.\n"); + goto undo_alloc; + } + m = ctx->mrec; + a = ctx->attr; + ll = sle64_to_cpu(a->lowest_vcn); + rl2 = ntfs_attr_find_vcn(mft_na, ll); + if (!rl2 || !rl2->length) { + ntfs_log_error("Failed to determine previous last " + "allocated cluster of mft data attribute.\n"); + if (rl2) + errno = EIO; + goto undo_alloc; + } + /* Get the size for the new mapping pairs array for this extent. */ + mp_size = ntfs_get_size_for_mapping_pairs(vol, rl2, ll, INT_MAX); + if (mp_size <= 0) { + ntfs_log_error("Get size for mapping pairs failed for " + "mft data attribute extent.\n"); + goto undo_alloc; + } + /* Expand the attribute record if necessary. */ + old_alen = le32_to_cpu(a->length); + if (ntfs_attr_record_resize(m, a, + mp_size + le16_to_cpu(a->mapping_pairs_offset))) { + ret = ntfs_mft_attr_extend(vol->mft_na); + if (ret == STATUS_OK) + goto ok; + if (ret == STATUS_ERROR) { + ntfs_log_perror("%s: ntfs_mft_attr_extend failed", __FUNCTION__); + update_mp = TRUE; + } + goto undo_alloc; + } + mp_rebuilt = TRUE; + /* + * Generate the mapping pairs array directly into the attribute record. + */ + if (ntfs_mapping_pairs_build(vol, + (u8*)a + le16_to_cpu(a->mapping_pairs_offset), mp_size, + rl2, ll, NULL)) { + ntfs_log_error("Failed to build mapping pairs array of " + "mft data attribute.\n"); + errno = EIO; + goto undo_alloc; + } + /* Update the highest_vcn. */ + a->highest_vcn = cpu_to_sle64(rl[1].vcn - 1); + /* + * We now have extended the mft data allocated_size by nr clusters. + * Reflect this in the ntfs_attr structure and the attribute record. + * @rl is the last (non-terminator) runlist element of mft data + * attribute. + */ + if (a->lowest_vcn) { + /* + * We are not in the first attribute extent, switch to it, but + * first ensure the changes will make it to disk later. + */ + ntfs_inode_mark_dirty(ctx->ntfs_ino); + ntfs_attr_reinit_search_ctx(ctx); + if (ntfs_attr_lookup(mft_na->type, mft_na->name, + mft_na->name_len, 0, 0, NULL, 0, ctx)) { + ntfs_log_error("Failed to find first attribute " + "extent of mft data attribute.\n"); + goto restore_undo_alloc; + } + a = ctx->attr; + } +ok: + mft_na->allocated_size += nr << vol->cluster_size_bits; + a->allocated_size = cpu_to_sle64(mft_na->allocated_size); + /* Ensure the changes make it to disk. */ + ntfs_inode_mark_dirty(ctx->ntfs_ino); + ntfs_attr_put_search_ctx(ctx); + ret = STATUS_OK; +out: + ntfs_log_leave("\n"); + return ret; + +restore_undo_alloc: + err = errno; + ntfs_attr_reinit_search_ctx(ctx); + if (ntfs_attr_lookup(mft_na->type, mft_na->name, mft_na->name_len, 0, + rl[1].vcn, NULL, 0, ctx)) { + ntfs_log_error("Failed to find last attribute extent of " + "mft data attribute.%s\n", es); + ntfs_attr_put_search_ctx(ctx); + mft_na->allocated_size += nr << vol->cluster_size_bits; + /* + * The only thing that is now wrong is ->allocated_size of the + * base attribute extent which chkdsk should be able to fix. + */ + errno = err; + ret = STATUS_ERROR; + goto out; + } + m = ctx->mrec; + a = ctx->attr; + a->highest_vcn = cpu_to_sle64(old_last_vcn - 1); + errno = err; +undo_alloc: + err = errno; + if (ntfs_cluster_free(vol, mft_na, old_last_vcn, -1) < 0) + ntfs_log_error("Failed to free clusters from mft data " + "attribute.%s\n", es); + if (ntfs_rl_truncate(&mft_na->rl, old_last_vcn)) + ntfs_log_error("Failed to truncate mft data attribute " + "runlist.%s\n", es); + if (mp_rebuilt) { + if (ntfs_mapping_pairs_build(vol, (u8*)a + + le16_to_cpu(a->mapping_pairs_offset), + old_alen - le16_to_cpu(a->mapping_pairs_offset), + rl2, ll, NULL)) + ntfs_log_error("Failed to restore mapping pairs " + "array.%s\n", es); + if (ntfs_attr_record_resize(m, a, old_alen)) + ntfs_log_error("Failed to restore attribute " + "record.%s\n", es); + ntfs_inode_mark_dirty(ctx->ntfs_ino); + } + if (update_mp) { + if (ntfs_attr_update_mapping_pairs(vol->mft_na, 0)) + ntfs_log_perror("%s: MP update failed", __FUNCTION__); + } + if (ctx) + ntfs_attr_put_search_ctx(ctx); + errno = err; + goto out; +} + + +static int ntfs_mft_record_init(ntfs_volume *vol, s64 size) +{ + int ret = -1; + ntfs_attr *mft_na, *mftbmp_na; + s64 old_data_initialized, old_data_size; + ntfs_attr_search_ctx *ctx; + + ntfs_log_enter("Entering\n"); + + /* NOTE: Caller must sanity check vol, vol->mft_na and vol->mftbmp_na */ + + mft_na = vol->mft_na; + mftbmp_na = vol->mftbmp_na; + + /* + * The mft record is outside the initialized data. Extend the mft data + * attribute until it covers the allocated record. The loop is only + * actually traversed more than once when a freshly formatted volume + * is first written to so it optimizes away nicely in the common case. + */ + ntfs_log_debug("Status of mft data before extension: " + "allocated_size 0x%llx, data_size 0x%llx, " + "initialized_size 0x%llx.\n", + (long long)mft_na->allocated_size, + (long long)mft_na->data_size, + (long long)mft_na->initialized_size); + while (size > mft_na->allocated_size) { + if (ntfs_mft_data_extend_allocation(vol) == STATUS_ERROR) + goto out; + ntfs_log_debug("Status of mft data after allocation extension: " + "allocated_size 0x%llx, data_size 0x%llx, " + "initialized_size 0x%llx.\n", + (long long)mft_na->allocated_size, + (long long)mft_na->data_size, + (long long)mft_na->initialized_size); + } + + old_data_initialized = mft_na->initialized_size; + old_data_size = mft_na->data_size; + + /* + * Extend mft data initialized size (and data size of course) to reach + * the allocated mft record, formatting the mft records along the way. + * Note: We only modify the ntfs_attr structure as that is all that is + * needed by ntfs_mft_record_format(). We will update the attribute + * record itself in one fell swoop later on. + */ + while (size > mft_na->initialized_size) { + s64 ll2 = mft_na->initialized_size >> vol->mft_record_size_bits; + mft_na->initialized_size += vol->mft_record_size; + if (mft_na->initialized_size > mft_na->data_size) + mft_na->data_size = mft_na->initialized_size; + ntfs_log_debug("Initializing mft record 0x%llx.\n", (long long)ll2); + if (ntfs_mft_record_format(vol, ll2) < 0) { + ntfs_log_perror("Failed to format mft record"); + goto undo_data_init; + } + } + + /* Update the mft data attribute record to reflect the new sizes. */ + ctx = ntfs_attr_get_search_ctx(mft_na->ni, NULL); + if (!ctx) + goto undo_data_init; + + if (ntfs_attr_lookup(mft_na->type, mft_na->name, mft_na->name_len, 0, + 0, NULL, 0, ctx)) { + ntfs_log_error("Failed to find first attribute extent of " + "mft data attribute.\n"); + ntfs_attr_put_search_ctx(ctx); + goto undo_data_init; + } + ctx->attr->initialized_size = cpu_to_sle64(mft_na->initialized_size); + ctx->attr->data_size = cpu_to_sle64(mft_na->data_size); + ctx->attr->allocated_size = cpu_to_sle64(mft_na->allocated_size); + + /* Ensure the changes make it to disk. */ + ntfs_inode_mark_dirty(ctx->ntfs_ino); + ntfs_attr_put_search_ctx(ctx); + ntfs_log_debug("Status of mft data after mft record initialization: " + "allocated_size 0x%llx, data_size 0x%llx, " + "initialized_size 0x%llx.\n", + (long long)mft_na->allocated_size, + (long long)mft_na->data_size, + (long long)mft_na->initialized_size); + + /* Sanity checks. */ + if (mft_na->data_size > mft_na->allocated_size || + mft_na->initialized_size > mft_na->data_size) + NTFS_BUG("mft_na sanity checks failed"); + + /* Sync MFT to minimize data loss if there won't be clean unmount. */ + if (ntfs_inode_sync(mft_na->ni)) + goto undo_data_init; + + ret = 0; +out: + ntfs_log_leave("\n"); + return ret; + +undo_data_init: + mft_na->initialized_size = old_data_initialized; + mft_na->data_size = old_data_size; + goto out; +} + +static int ntfs_mft_rec_init(ntfs_volume *vol, s64 size) +{ + int ret = -1; + ntfs_attr *mft_na, *mftbmp_na; + s64 old_data_initialized, old_data_size; + ntfs_attr_search_ctx *ctx; + + ntfs_log_enter("Entering\n"); + + mft_na = vol->mft_na; + mftbmp_na = vol->mftbmp_na; + + if (size > mft_na->allocated_size || size > mft_na->initialized_size) { + errno = EIO; + ntfs_log_perror("%s: unexpected $MFT sizes, see below", __FUNCTION__); + ntfs_log_error("$MFT: size=%lld allocated_size=%lld " + "data_size=%lld initialized_size=%lld\n", + (long long)size, + (long long)mft_na->allocated_size, + (long long)mft_na->data_size, + (long long)mft_na->initialized_size); + goto out; + } + + old_data_initialized = mft_na->initialized_size; + old_data_size = mft_na->data_size; + + /* Update the mft data attribute record to reflect the new sizes. */ + ctx = ntfs_attr_get_search_ctx(mft_na->ni, NULL); + if (!ctx) + goto undo_data_init; + + if (ntfs_attr_lookup(mft_na->type, mft_na->name, mft_na->name_len, 0, + 0, NULL, 0, ctx)) { + ntfs_log_error("Failed to find first attribute extent of " + "mft data attribute.\n"); + ntfs_attr_put_search_ctx(ctx); + goto undo_data_init; + } + ctx->attr->initialized_size = cpu_to_sle64(mft_na->initialized_size); + ctx->attr->data_size = cpu_to_sle64(mft_na->data_size); + + /* CHECKME: ctx->attr->allocation_size is already ok? */ + + /* Ensure the changes make it to disk. */ + ntfs_inode_mark_dirty(ctx->ntfs_ino); + ntfs_attr_put_search_ctx(ctx); + + /* Sanity checks. */ + if (mft_na->data_size > mft_na->allocated_size || + mft_na->initialized_size > mft_na->data_size) + NTFS_BUG("mft_na sanity checks failed"); +out: + ntfs_log_leave("\n"); + return ret; + +undo_data_init: + mft_na->initialized_size = old_data_initialized; + mft_na->data_size = old_data_size; + goto out; +} + +static ntfs_inode *ntfs_mft_rec_alloc(ntfs_volume *vol) +{ + s64 ll, bit; + ntfs_attr *mft_na, *mftbmp_na; + MFT_RECORD *m; + ntfs_inode *ni = NULL; + ntfs_inode *base_ni; + int err; + le16 seq_no, usn; + + ntfs_log_enter("Entering\n"); + + mft_na = vol->mft_na; + mftbmp_na = vol->mftbmp_na; + + base_ni = mft_na->ni; + + bit = ntfs_mft_bitmap_find_free_rec(vol, base_ni); + if (bit >= 0) + goto found_free_rec; + + if (errno != ENOSPC) + goto out; + + errno = ENOSPC; + /* strerror() is intentionally used below, we want to log this error. */ + ntfs_log_error("No free mft record for $MFT: %s\n", strerror(errno)); + goto err_out; + +found_free_rec: + if (ntfs_bitmap_set_bit(mftbmp_na, bit)) { + ntfs_log_error("Failed to allocate bit in mft bitmap #2\n"); + goto err_out; + } + + ll = (bit + 1) << vol->mft_record_size_bits; + if (ll > mft_na->initialized_size) + if (ntfs_mft_rec_init(vol, ll) < 0) + goto undo_mftbmp_alloc; + /* + * We now have allocated and initialized the mft record. Need to read + * it from disk and re-format it, preserving the sequence number if it + * is not zero as well as the update sequence number if it is not zero + * or -1 (0xffff). + */ + m = ntfs_malloc(vol->mft_record_size); + if (!m) + goto undo_mftbmp_alloc; + + if (ntfs_mft_record_read(vol, bit, m)) { + free(m); + goto undo_mftbmp_alloc; + } + /* Sanity check that the mft record is really not in use. */ + if (ntfs_is_file_record(m->magic) && (m->flags & MFT_RECORD_IN_USE)) { + ntfs_log_error("Inode %lld is used but it wasn't marked in " + "$MFT bitmap. Fixed.\n", (long long)bit); + free(m); + goto undo_mftbmp_alloc; + } + + seq_no = m->sequence_number; + usn = *(le16*)((u8*)m + le16_to_cpu(m->usa_ofs)); + if (ntfs_mft_record_layout(vol, bit, m)) { + ntfs_log_error("Failed to re-format mft record.\n"); + free(m); + goto undo_mftbmp_alloc; + } + if (seq_no) + m->sequence_number = seq_no; + seq_no = usn; + if (seq_no && seq_no != const_cpu_to_le16(0xffff)) + *(le16*)((u8*)m + le16_to_cpu(m->usa_ofs)) = usn; + /* Set the mft record itself in use. */ + m->flags |= MFT_RECORD_IN_USE; + /* Now need to open an ntfs inode for the mft record. */ + ni = ntfs_inode_allocate(vol); + if (!ni) { + ntfs_log_error("Failed to allocate buffer for inode.\n"); + free(m); + goto undo_mftbmp_alloc; + } + ni->mft_no = bit; + ni->mrec = m; + /* + * If we are allocating an extent mft record, make the opened inode an + * extent inode and attach it to the base inode. Also, set the base + * mft record reference in the extent inode. + */ + ni->nr_extents = -1; + ni->base_ni = base_ni; + m->base_mft_record = MK_LE_MREF(base_ni->mft_no, + le16_to_cpu(base_ni->mrec->sequence_number)); + /* + * Attach the extent inode to the base inode, reallocating + * memory if needed. + */ + if (!(base_ni->nr_extents & 3)) { + ntfs_inode **extent_nis; + int i; + + i = (base_ni->nr_extents + 4) * sizeof(ntfs_inode *); + extent_nis = ntfs_malloc(i); + if (!extent_nis) { + free(m); + free(ni); + goto undo_mftbmp_alloc; + } + if (base_ni->nr_extents) { + memcpy(extent_nis, base_ni->extent_nis, + i - 4 * sizeof(ntfs_inode *)); + free(base_ni->extent_nis); + } + base_ni->extent_nis = extent_nis; + } + base_ni->extent_nis[base_ni->nr_extents++] = ni; + + /* Make sure the allocated inode is written out to disk later. */ + ntfs_inode_mark_dirty(ni); + /* Initialize time, allocated and data size in ntfs_inode struct. */ + ni->data_size = ni->allocated_size = 0; + ni->flags = 0; + ni->creation_time = ni->last_data_change_time = + ni->last_mft_change_time = + ni->last_access_time = ntfs_current_time(); + /* Update the default mft allocation position if it was used. */ + if (!base_ni) + vol->mft_data_pos = bit + 1; + /* Return the opened, allocated inode of the allocated mft record. */ + ntfs_log_error("allocated %sinode %lld\n", + base_ni ? "extent " : "", (long long)bit); +out: + ntfs_log_leave("\n"); + return ni; + +undo_mftbmp_alloc: + err = errno; + if (ntfs_bitmap_clear_bit(mftbmp_na, bit)) + ntfs_log_error("Failed to clear bit in mft bitmap.%s\n", es); + errno = err; +err_out: + if (!errno) + errno = EIO; + ni = NULL; + goto out; +} + +/** + * ntfs_mft_record_alloc - allocate an mft record on an ntfs volume + * @vol: volume on which to allocate the mft record + * @base_ni: open base inode if allocating an extent mft record or NULL + * + * Allocate an mft record in $MFT/$DATA of an open ntfs volume @vol. + * + * If @base_ni is NULL make the mft record a base mft record and allocate it at + * the default allocator position. + * + * If @base_ni is not NULL make the allocated mft record an extent record, + * allocate it starting at the mft record after the base mft record and attach + * the allocated and opened ntfs inode to the base inode @base_ni. + * + * On success return the now opened ntfs (extent) inode of the mft record. + * + * On error return NULL with errno set to the error code. + * + * To find a free mft record, we scan the mft bitmap for a zero bit. To + * optimize this we start scanning at the place specified by @base_ni or if + * @base_ni is NULL we start where we last stopped and we perform wrap around + * when we reach the end. Note, we do not try to allocate mft records below + * number 24 because numbers 0 to 15 are the defined system files anyway and 16 + * to 24 are special in that they are used for storing extension mft records + * for the $DATA attribute of $MFT. This is required to avoid the possibility + * of creating a run list with a circular dependence which once written to disk + * can never be read in again. Windows will only use records 16 to 24 for + * normal files if the volume is completely out of space. We never use them + * which means that when the volume is really out of space we cannot create any + * more files while Windows can still create up to 8 small files. We can start + * doing this at some later time, it does not matter much for now. + * + * When scanning the mft bitmap, we only search up to the last allocated mft + * record. If there are no free records left in the range 24 to number of + * allocated mft records, then we extend the $MFT/$DATA attribute in order to + * create free mft records. We extend the allocated size of $MFT/$DATA by 16 + * records at a time or one cluster, if cluster size is above 16kiB. If there + * is not sufficient space to do this, we try to extend by a single mft record + * or one cluster, if cluster size is above the mft record size, but we only do + * this if there is enough free space, which we know from the values returned + * by the failed cluster allocation function when we tried to do the first + * allocation. + * + * No matter how many mft records we allocate, we initialize only the first + * allocated mft record, incrementing mft data size and initialized size + * accordingly, open an ntfs_inode for it and return it to the caller, unless + * there are less than 24 mft records, in which case we allocate and initialize + * mft records until we reach record 24 which we consider as the first free mft + * record for use by normal files. + * + * If during any stage we overflow the initialized data in the mft bitmap, we + * extend the initialized size (and data size) by 8 bytes, allocating another + * cluster if required. The bitmap data size has to be at least equal to the + * number of mft records in the mft, but it can be bigger, in which case the + * superfluous bits are padded with zeroes. + * + * Thus, when we return successfully (return value non-zero), we will have: + * - initialized / extended the mft bitmap if necessary, + * - initialized / extended the mft data if necessary, + * - set the bit corresponding to the mft record being allocated in the + * mft bitmap, + * - open an ntfs_inode for the allocated mft record, and we will + * - return the ntfs_inode. + * + * On error (return value zero), nothing will have changed. If we had changed + * anything before the error occurred, we will have reverted back to the + * starting state before returning to the caller. Thus, except for bugs, we + * should always leave the volume in a consistent state when returning from + * this function. + * + * Note, this function cannot make use of most of the normal functions, like + * for example for attribute resizing, etc, because when the run list overflows + * the base mft record and an attribute list is used, it is very important that + * the extension mft records used to store the $DATA attribute of $MFT can be + * reached without having to read the information contained inside them, as + * this would make it impossible to find them in the first place after the + * volume is dismounted. $MFT/$BITMAP probably does not need to follow this + * rule because the bitmap is not essential for finding the mft records, but on + * the other hand, handling the bitmap in this special way would make life + * easier because otherwise there might be circular invocations of functions + * when reading the bitmap but if we are careful, we should be able to avoid + * all problems. + */ +ntfs_inode *ntfs_mft_record_alloc(ntfs_volume *vol, ntfs_inode *base_ni) +{ + s64 ll, bit; + ntfs_attr *mft_na, *mftbmp_na; + MFT_RECORD *m; + ntfs_inode *ni = NULL; + int err; + le16 seq_no, usn; + + if (base_ni) + ntfs_log_enter("Entering (allocating an extent mft record for " + "base mft record %lld).\n", + (long long)base_ni->mft_no); + else + ntfs_log_enter("Entering (allocating a base mft record)\n"); + if (!vol || !vol->mft_na || !vol->mftbmp_na) { + errno = EINVAL; + goto out; + } + + if (ntfs_is_mft(base_ni)) { + ni = ntfs_mft_rec_alloc(vol); + goto out; + } + + mft_na = vol->mft_na; + mftbmp_na = vol->mftbmp_na; +retry: + bit = ntfs_mft_bitmap_find_free_rec(vol, base_ni); + if (bit >= 0) { + ntfs_log_debug("found free record (#1) at %lld\n", + (long long)bit); + goto found_free_rec; + } + if (errno != ENOSPC) + goto out; + /* + * No free mft records left. If the mft bitmap already covers more + * than the currently used mft records, the next records are all free, + * so we can simply allocate the first unused mft record. + * Note: We also have to make sure that the mft bitmap at least covers + * the first 24 mft records as they are special and whilst they may not + * be in use, we do not allocate from them. + */ + ll = mft_na->initialized_size >> vol->mft_record_size_bits; + if (mftbmp_na->initialized_size << 3 > ll && + mftbmp_na->initialized_size > RESERVED_MFT_RECORDS / 8) { + bit = ll; + if (bit < RESERVED_MFT_RECORDS) + bit = RESERVED_MFT_RECORDS; + ntfs_log_debug("found free record (#2) at %lld\n", + (long long)bit); + goto found_free_rec; + } + /* + * The mft bitmap needs to be expanded until it covers the first unused + * mft record that we can allocate. + * Note: The smallest mft record we allocate is mft record 24. + */ + ntfs_log_debug("Status of mftbmp before extension: allocated_size 0x%llx, " + "data_size 0x%llx, initialized_size 0x%llx.\n", + (long long)mftbmp_na->allocated_size, + (long long)mftbmp_na->data_size, + (long long)mftbmp_na->initialized_size); + if (mftbmp_na->initialized_size + 8 > mftbmp_na->allocated_size) { + + int ret = ntfs_mft_bitmap_extend_allocation(vol); + + if (ret == STATUS_ERROR) + goto err_out; + if (ret == STATUS_KEEP_SEARCHING) { + ret = ntfs_mft_bitmap_extend_allocation(vol); + if (ret != STATUS_OK) + goto err_out; + } + + ntfs_log_debug("Status of mftbmp after allocation extension: " + "allocated_size 0x%llx, data_size 0x%llx, " + "initialized_size 0x%llx.\n", + (long long)mftbmp_na->allocated_size, + (long long)mftbmp_na->data_size, + (long long)mftbmp_na->initialized_size); + } + /* + * We now have sufficient allocated space, extend the initialized_size + * as well as the data_size if necessary and fill the new space with + * zeroes. + */ + bit = mftbmp_na->initialized_size << 3; + if (ntfs_mft_bitmap_extend_initialized(vol)) + goto err_out; + ntfs_log_debug("Status of mftbmp after initialized extension: " + "allocated_size 0x%llx, data_size 0x%llx, " + "initialized_size 0x%llx.\n", + (long long)mftbmp_na->allocated_size, + (long long)mftbmp_na->data_size, + (long long)mftbmp_na->initialized_size); + ntfs_log_debug("found free record (#3) at %lld\n", (long long)bit); +found_free_rec: + /* @bit is the found free mft record, allocate it in the mft bitmap. */ + if (ntfs_bitmap_set_bit(mftbmp_na, bit)) { + ntfs_log_error("Failed to allocate bit in mft bitmap.\n"); + goto err_out; + } + + /* The mft bitmap is now uptodate. Deal with mft data attribute now. */ + ll = (bit + 1) << vol->mft_record_size_bits; + if (ll > mft_na->initialized_size) + if (ntfs_mft_record_init(vol, ll) < 0) + goto undo_mftbmp_alloc; + + /* + * We now have allocated and initialized the mft record. Need to read + * it from disk and re-format it, preserving the sequence number if it + * is not zero as well as the update sequence number if it is not zero + * or -1 (0xffff). + */ + m = ntfs_malloc(vol->mft_record_size); + if (!m) + goto undo_mftbmp_alloc; + + if (ntfs_mft_record_read(vol, bit, m)) { + free(m); + goto undo_mftbmp_alloc; + } + /* Sanity check that the mft record is really not in use. */ + if (ntfs_is_file_record(m->magic) && (m->flags & MFT_RECORD_IN_USE)) { + ntfs_log_error("Inode %lld is used but it wasn't marked in " + "$MFT bitmap. Fixed.\n", (long long)bit); + free(m); + goto retry; + } + seq_no = m->sequence_number; + usn = *(le16*)((u8*)m + le16_to_cpu(m->usa_ofs)); + if (ntfs_mft_record_layout(vol, bit, m)) { + ntfs_log_error("Failed to re-format mft record.\n"); + free(m); + goto undo_mftbmp_alloc; + } + if (seq_no) + m->sequence_number = seq_no; + seq_no = usn; + if (seq_no && seq_no != const_cpu_to_le16(0xffff)) + *(le16*)((u8*)m + le16_to_cpu(m->usa_ofs)) = usn; + /* Set the mft record itself in use. */ + m->flags |= MFT_RECORD_IN_USE; + /* Now need to open an ntfs inode for the mft record. */ + ni = ntfs_inode_allocate(vol); + if (!ni) { + ntfs_log_error("Failed to allocate buffer for inode.\n"); + free(m); + goto undo_mftbmp_alloc; + } + ni->mft_no = bit; + ni->mrec = m; + /* + * If we are allocating an extent mft record, make the opened inode an + * extent inode and attach it to the base inode. Also, set the base + * mft record reference in the extent inode. + */ + if (base_ni) { + ni->nr_extents = -1; + ni->base_ni = base_ni; + m->base_mft_record = MK_LE_MREF(base_ni->mft_no, + le16_to_cpu(base_ni->mrec->sequence_number)); + /* + * Attach the extent inode to the base inode, reallocating + * memory if needed. + */ + if (!(base_ni->nr_extents & 3)) { + ntfs_inode **extent_nis; + int i; + + i = (base_ni->nr_extents + 4) * sizeof(ntfs_inode *); + extent_nis = ntfs_malloc(i); + if (!extent_nis) { + free(m); + free(ni); + goto undo_mftbmp_alloc; + } + if (base_ni->nr_extents) { + memcpy(extent_nis, base_ni->extent_nis, + i - 4 * sizeof(ntfs_inode *)); + free(base_ni->extent_nis); + } + base_ni->extent_nis = extent_nis; + } + base_ni->extent_nis[base_ni->nr_extents++] = ni; + } + /* Make sure the allocated inode is written out to disk later. */ + ntfs_inode_mark_dirty(ni); + /* Initialize time, allocated and data size in ntfs_inode struct. */ + ni->data_size = ni->allocated_size = 0; + ni->flags = 0; + ni->creation_time = ni->last_data_change_time = + ni->last_mft_change_time = + ni->last_access_time = ntfs_current_time(); + /* Update the default mft allocation position if it was used. */ + if (!base_ni) + vol->mft_data_pos = bit + 1; + /* Return the opened, allocated inode of the allocated mft record. */ + ntfs_log_debug("allocated %sinode 0x%llx.\n", + base_ni ? "extent " : "", (long long)bit); + vol->free_mft_records--; +out: + ntfs_log_leave("\n"); + return ni; + +undo_mftbmp_alloc: + err = errno; + if (ntfs_bitmap_clear_bit(mftbmp_na, bit)) + ntfs_log_error("Failed to clear bit in mft bitmap.%s\n", es); + errno = err; +err_out: + if (!errno) + errno = EIO; + ni = NULL; + goto out; +} + +/** + * ntfs_mft_record_free - free an mft record on an ntfs volume + * @vol: volume on which to free the mft record + * @ni: open ntfs inode of the mft record to free + * + * Free the mft record of the open inode @ni on the mounted ntfs volume @vol. + * Note that this function calls ntfs_inode_close() internally and hence you + * cannot use the pointer @ni any more after this function returns success. + * + * On success return 0 and on error return -1 with errno set to the error code. + */ +int ntfs_mft_record_free(ntfs_volume *vol, ntfs_inode *ni) +{ + u64 mft_no; + int err; + u16 seq_no; + le16 old_seq_no; + + ntfs_log_trace("Entering for inode 0x%llx.\n", (long long) ni->mft_no); + + if (!vol || !vol->mftbmp_na || !ni) { + errno = EINVAL; + return -1; + } + + /* Cache the mft reference for later. */ + mft_no = ni->mft_no; + + /* Mark the mft record as not in use. */ + ni->mrec->flags &= ~MFT_RECORD_IN_USE; + + /* Increment the sequence number, skipping zero, if it is not zero. */ + old_seq_no = ni->mrec->sequence_number; + seq_no = le16_to_cpu(old_seq_no); + if (seq_no == 0xffff) + seq_no = 1; + else if (seq_no) + seq_no++; + ni->mrec->sequence_number = cpu_to_le16(seq_no); + + /* Set the inode dirty and write it out. */ + ntfs_inode_mark_dirty(ni); + if (ntfs_inode_sync(ni)) { + err = errno; + goto sync_rollback; + } + + /* Clear the bit in the $MFT/$BITMAP corresponding to this record. */ + if (ntfs_bitmap_clear_bit(vol->mftbmp_na, mft_no)) { + err = errno; + // FIXME: If ntfs_bitmap_clear_run() guarantees rollback on + // error, this could be changed to goto sync_rollback; + goto bitmap_rollback; + } + + /* Throw away the now freed inode. */ +#if CACHE_NIDATA_SIZE + if (!ntfs_inode_real_close(ni)) { +#else + if (!ntfs_inode_close(ni)) { +#endif + vol->free_mft_records++; + return 0; + } + err = errno; + + /* Rollback what we did... */ +bitmap_rollback: + if (ntfs_bitmap_set_bit(vol->mftbmp_na, mft_no)) + ntfs_log_debug("Eeek! Rollback failed in ntfs_mft_record_free(). " + "Leaving inconsistent metadata!\n"); +sync_rollback: + ni->mrec->flags |= MFT_RECORD_IN_USE; + ni->mrec->sequence_number = old_seq_no; + ntfs_inode_mark_dirty(ni); + errno = err; + return -1; +} + +/** + * ntfs_mft_usn_dec - Decrement USN by one + * @mrec: pointer to an mft record + * + * On success return 0 and on error return -1 with errno set. + */ +int ntfs_mft_usn_dec(MFT_RECORD *mrec) +{ + u16 usn; + le16 *usnp; + + if (!mrec) { + errno = EINVAL; + return -1; + } + usnp = (le16*)((char*)mrec + le16_to_cpu(mrec->usa_ofs)); + usn = le16_to_cpup(usnp); + if (usn-- <= 1) + usn = 0xfffe; + *usnp = cpu_to_le16(usn); + + return 0; +} + diff --git a/libntfs-3g/misc.c b/libntfs-3g/misc.c new file mode 100755 index 0000000..b2e17cb --- a/dev/null +++ b/libntfs-3g/misc.c @@ -0,0 +1,61 @@ +/** + * misc.c : miscellaneous : + * - dealing with errors in memory allocation + * + * Copyright (c) 2008 Jean-Pierre Andre + * + * This program/include file 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/include file 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 (in the main directory of the NTFS-3G + * distribution in the file COPYING); if not, write to the Free Software + * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif + +#include "types.h" +#include "misc.h" +#include "logging.h" + +/** + * ntfs_calloc + * + * Return a pointer to the allocated memory or NULL if the request fails. + */ +void *ntfs_calloc(size_t size) +{ + void *p; + + p = calloc(1, size); + if (!p) + ntfs_log_perror("Failed to calloc %lld bytes", (long long)size); + return p; +} + +void *ntfs_malloc(size_t size) +{ + void *p; + + p = malloc(size); + if (!p) + ntfs_log_perror("Failed to malloc %lld bytes", (long long)size); + return p; +} diff --git a/libntfs-3g/mst.c b/libntfs-3g/mst.c new file mode 100755 index 0000000..470942d --- a/dev/null +++ b/libntfs-3g/mst.c @@ -0,0 +1,231 @@ +/** + * mst.c - Multi sector fixup handling code. Originated from the Linux-NTFS project. + * + * Copyright (c) 2000-2004 Anton Altaparmakov + * Copyright (c) 2006-2009 Szabolcs Szakacsits + * + * This program/include file 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/include file 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 (in the main directory of the NTFS-3G + * distribution in the file COPYING); if not, write to the Free Software + * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_ERRNO_H +#include +#endif + +#include "mst.h" +#include "logging.h" + +/** + * ntfs_mst_post_read_fixup - deprotect multi sector transfer protected data + * @b: pointer to the data to deprotect + * @size: size in bytes of @b + * + * Perform the necessary post read multi sector transfer fixups and detect the + * presence of incomplete multi sector transfers. - In that case, overwrite the + * magic of the ntfs record header being processed with "BAAD" (in memory only!) + * and abort processing. + * + * Return 0 on success and -1 on error, with errno set to the error code. The + * following error codes are defined: + * EINVAL Invalid arguments or invalid NTFS record in buffer @b. + * EIO Multi sector transfer error was detected. Magic of the NTFS + * record in @b will have been set to "BAAD". + */ +int ntfs_mst_post_read_fixup(NTFS_RECORD *b, const u32 size) +{ + u16 usa_ofs, usa_count, usn; + u16 *usa_pos, *data_pos; + + ntfs_log_trace("Entering\n"); + + /* Setup the variables. */ + usa_ofs = le16_to_cpu(b->usa_ofs); + /* Decrement usa_count to get number of fixups. */ + usa_count = le16_to_cpu(b->usa_count) - 1; + /* Size and alignment checks. */ + if (size & (NTFS_BLOCK_SIZE - 1) || usa_ofs & 1 || + (u32)(usa_ofs + (usa_count * 2)) > size || + (size >> NTFS_BLOCK_SIZE_BITS) != usa_count) { + errno = EINVAL; + ntfs_log_perror("%s: magic: 0x%08x size: %d usa_ofs: %d " + "usa_count: %d", __FUNCTION__, *(le32 *)b, + size, usa_ofs, usa_count); + return -1; + } + /* Position of usn in update sequence array. */ + usa_pos = (u16*)b + usa_ofs/sizeof(u16); + /* + * The update sequence number which has to be equal to each of the + * u16 values before they are fixed up. Note no need to care for + * endianness since we are comparing and moving data for on disk + * structures which means the data is consistent. - If it is + * consistency the wrong endianness it doesn't make any difference. + */ + usn = *usa_pos; + /* + * Position in protected data of first u16 that needs fixing up. + */ + data_pos = (u16*)b + NTFS_BLOCK_SIZE/sizeof(u16) - 1; + /* + * Check for incomplete multi sector transfer(s). + */ + while (usa_count--) { + if (*data_pos != usn) { + /* + * Incomplete multi sector transfer detected! )-: + * Set the magic to "BAAD" and return failure. + * Note that magic_BAAD is already converted to le32. + */ + errno = EIO; + ntfs_log_perror("Incomplete multi-sector transfer: " + "magic: 0x%08x size: %d usa_ofs: %d usa_count:" + " %d data: %d usn: %d", *(le32 *)b, size, + usa_ofs, usa_count, *data_pos, usn); + b->magic = magic_BAAD; + return -1; + } + data_pos += NTFS_BLOCK_SIZE/sizeof(u16); + } + /* Re-setup the variables. */ + usa_count = le16_to_cpu(b->usa_count) - 1; + data_pos = (u16*)b + NTFS_BLOCK_SIZE/sizeof(u16) - 1; + /* Fixup all sectors. */ + while (usa_count--) { + /* + * Increment position in usa and restore original data from + * the usa into the data buffer. + */ + *data_pos = *(++usa_pos); + /* Increment position in data as well. */ + data_pos += NTFS_BLOCK_SIZE/sizeof(u16); + } + return 0; +} + +/** + * ntfs_mst_pre_write_fixup - apply multi sector transfer protection + * @b: pointer to the data to protect + * @size: size in bytes of @b + * + * Perform the necessary pre write multi sector transfer fixup on the data + * pointer to by @b of @size. + * + * Return 0 if fixups applied successfully or -1 if no fixups were performed + * due to errors. In that case errno i set to the error code (EINVAL). + * + * NOTE: We consider the absence / invalidity of an update sequence array to + * mean error. This means that you have to create a valid update sequence + * array header in the ntfs record before calling this function, otherwise it + * will fail (the header needs to contain the position of the update sequence + * array together with the number of elements in the array). You also need to + * initialise the update sequence number before calling this function + * otherwise a random word will be used (whatever was in the record at that + * position at that time). + */ +int ntfs_mst_pre_write_fixup(NTFS_RECORD *b, const u32 size) +{ + u16 usa_ofs, usa_count, usn; + u16 *usa_pos, *data_pos; + + ntfs_log_trace("Entering\n"); + + /* Sanity check + only fixup if it makes sense. */ + if (!b || ntfs_is_baad_record(b->magic) || + ntfs_is_hole_record(b->magic)) { + errno = EINVAL; + ntfs_log_perror("%s: bad argument", __FUNCTION__); + return -1; + } + /* Setup the variables. */ + usa_ofs = le16_to_cpu(b->usa_ofs); + /* Decrement usa_count to get number of fixups. */ + usa_count = le16_to_cpu(b->usa_count) - 1; + /* Size and alignment checks. */ + if (size & (NTFS_BLOCK_SIZE - 1) || usa_ofs & 1 || + (u32)(usa_ofs + (usa_count * 2)) > size || + (size >> NTFS_BLOCK_SIZE_BITS) != usa_count) { + errno = EINVAL; + ntfs_log_perror("%s", __FUNCTION__); + return -1; + } + /* Position of usn in update sequence array. */ + usa_pos = (u16*)((u8*)b + usa_ofs); + /* + * Cyclically increment the update sequence number + * (skipping 0 and -1, i.e. 0xffff). + */ + usn = le16_to_cpup(usa_pos) + 1; + if (usn == 0xffff || !usn) + usn = 1; + usn = cpu_to_le16(usn); + *usa_pos = usn; + /* Position in data of first u16 that needs fixing up. */ + data_pos = (u16*)b + NTFS_BLOCK_SIZE/sizeof(u16) - 1; + /* Fixup all sectors. */ + while (usa_count--) { + /* + * Increment the position in the usa and save the + * original data from the data buffer into the usa. + */ + *(++usa_pos) = *data_pos; + /* Apply fixup to data. */ + *data_pos = usn; + /* Increment position in data as well. */ + data_pos += NTFS_BLOCK_SIZE/sizeof(u16); + } + return 0; +} + +/** + * ntfs_mst_post_write_fixup - deprotect multi sector transfer protected data + * @b: pointer to the data to deprotect + * + * Perform the necessary post write multi sector transfer fixup, not checking + * for any errors, because we assume we have just used + * ntfs_mst_pre_write_fixup(), thus the data will be fine or we would never + * have gotten here. + */ +void ntfs_mst_post_write_fixup(NTFS_RECORD *b) +{ + u16 *usa_pos, *data_pos; + + u16 usa_ofs = le16_to_cpu(b->usa_ofs); + u16 usa_count = le16_to_cpu(b->usa_count) - 1; + + ntfs_log_trace("Entering\n"); + + /* Position of usn in update sequence array. */ + usa_pos = (u16*)b + usa_ofs/sizeof(u16); + + /* Position in protected data of first u16 that needs fixing up. */ + data_pos = (u16*)b + NTFS_BLOCK_SIZE/sizeof(u16) - 1; + + /* Fixup all sectors. */ + while (usa_count--) { + /* + * Increment position in usa and restore original data from + * the usa into the data buffer. + */ + *data_pos = *(++usa_pos); + + /* Increment position in data as well. */ + data_pos += NTFS_BLOCK_SIZE/sizeof(u16); + } +} + diff --git a/libntfs-3g/object_id.c b/libntfs-3g/object_id.c new file mode 100755 index 0000000..555dd13 --- a/dev/null +++ b/libntfs-3g/object_id.c @@ -0,0 +1,637 @@ +/** + * object_id.c - Processing of object ids + * + * This module is part of ntfs-3g library + * + * Copyright (c) 2009 Jean-Pierre Andre + * + * This program/include file 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/include file 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 (in the main directory of the NTFS-3G + * distribution in the file COPYING); if not, write to the Free Software + * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_ERRNO_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_SYS_STAT_H +#include +#endif + +#ifdef HAVE_SETXATTR +#include +#endif + +#ifdef HAVE_SYS_SYSMACROS_H +#include +#endif + +#include "types.h" +#include "debug.h" +#include "attrib.h" +#include "inode.h" +#include "dir.h" +#include "volume.h" +#include "mft.h" +#include "index.h" +#include "lcnalloc.h" +#include "object_id.h" +#include "logging.h" +#include "misc.h" + +/* + * Endianness considerations + * + * According to RFC 4122, GUIDs should be printed with the most + * significant byte first, and the six fields be compared individually + * for ordering. RFC 4122 does not define the internal representation. + * + * Here we always copy disk images with no endianness change, + * and, for indexing, GUIDs are compared as if they were a sequence + * of four unsigned 32 bit integers. + * + * --------------------- begin from RFC 4122 ---------------------- + * Consider each field of the UUID to be an unsigned integer as shown + * in the table in section Section 4.1.2. Then, to compare a pair of + * UUIDs, arithmetically compare the corresponding fields from each + * UUID in order of significance and according to their data type. + * Two UUIDs are equal if and only if all the corresponding fields + * are equal. + * + * UUIDs, as defined in this document, can also be ordered + * lexicographically. For a pair of UUIDs, the first one follows the + * second if the most significant field in which the UUIDs differ is + * greater for the first UUID. The second precedes the first if the + * most significant field in which the UUIDs differ is greater for + * the second UUID. + * + * The fields are encoded as 16 octets, with the sizes and order of the + * fields defined above, and with each field encoded with the Most + * Significant Byte first (known as network byte order). Note that the + * field names, particularly for multiplexed fields, follow historical + * practice. + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | time_low | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | time_mid | time_hi_and_version | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |clk_seq_hi_res | clk_seq_low | node (0-1) | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | node (2-5) | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * ---------------------- end from RFC 4122 ----------------------- + */ + +typedef struct { + GUID object_id; +} OBJECT_ID_INDEX_KEY; + +typedef struct { + le64 file_id; + GUID birth_volume_id; + GUID birth_object_id; + GUID domain_id; +} OBJECT_ID_INDEX_DATA; // known as OBJ_ID_INDEX_DATA + +struct OBJECT_ID_INDEX { /* index entry in $Extend/$ObjId */ + INDEX_ENTRY_HEADER header; + OBJECT_ID_INDEX_KEY key; + OBJECT_ID_INDEX_DATA data; +} ; + +static ntfschar objid_index_name[] = { const_cpu_to_le16('$'), + const_cpu_to_le16('O') }; +#ifdef HAVE_SETXATTR /* extended attributes interface required */ + +/* + * Set the index for a new object id + * + * Returns 0 if success + * -1 if failure, explained by errno + */ + +static int set_object_id_index(ntfs_inode *ni, ntfs_index_context *xo, + const OBJECT_ID_ATTR *object_id) +{ + struct OBJECT_ID_INDEX indx; + u64 file_id_cpu; + le64 file_id; + le16 seqn; + + seqn = ni->mrec->sequence_number; + file_id_cpu = MK_MREF(ni->mft_no,le16_to_cpu(seqn)); + file_id = cpu_to_le64(file_id_cpu); + indx.header.data_offset = const_cpu_to_le16( + sizeof(INDEX_ENTRY_HEADER) + + sizeof(OBJECT_ID_INDEX_KEY)); + indx.header.data_length = const_cpu_to_le16( + sizeof(OBJECT_ID_INDEX_DATA)); + indx.header.reservedV = const_cpu_to_le32(0); + indx.header.length = const_cpu_to_le16( + sizeof(struct OBJECT_ID_INDEX)); + indx.header.key_length = const_cpu_to_le16( + sizeof(OBJECT_ID_INDEX_KEY)); + indx.header.flags = const_cpu_to_le16(0); + indx.header.reserved = const_cpu_to_le16(0); + + memcpy(&indx.key.object_id,object_id,sizeof(GUID)); + + indx.data.file_id = file_id; + memcpy(&indx.data.birth_volume_id, + &object_id->birth_volume_id,sizeof(GUID)); + memcpy(&indx.data.birth_object_id, + &object_id->birth_object_id,sizeof(GUID)); + memcpy(&indx.data.domain_id, + &object_id->domain_id,sizeof(GUID)); + ntfs_index_ctx_reinit(xo); + return (ntfs_ie_add(xo,(INDEX_ENTRY*)&indx)); +} + +#endif /* HAVE_SETXATTR */ + +/* + * Open the $Extend/$ObjId file and its index + * + * Return the index context if opened + * or NULL if an error occurred (errno tells why) + * + * The index has to be freed and inode closed when not needed any more. + */ + +static ntfs_index_context *open_object_id_index(ntfs_volume *vol) +{ + u64 inum; + ntfs_inode *ni; + ntfs_inode *dir_ni; + ntfs_index_context *xo; + + /* do not use path_name_to inode - could reopen root */ + dir_ni = ntfs_inode_open(vol, FILE_Extend); + ni = (ntfs_inode*)NULL; + if (dir_ni) { + inum = ntfs_inode_lookup_by_mbsname(dir_ni,"$ObjId"); + if (inum != (u64)-1) + ni = ntfs_inode_open(vol, inum); + ntfs_inode_close(dir_ni); + } + if (ni) { + xo = ntfs_index_ctx_get(ni, objid_index_name, 2); + if (!xo) { + ntfs_inode_close(ni); + } + } else + xo = (ntfs_index_context*)NULL; + return (xo); +} + +#ifdef HAVE_SETXATTR /* extended attributes interface required */ + +/* + * Merge object_id data stored in the index into + * a full object_id struct. + * + * returns 0 if merging successful + * -1 if no data could be merged. This is generally not an error + */ + +static int merge_index_data(ntfs_inode *ni, + const OBJECT_ID_ATTR *objectid_attr, + OBJECT_ID_ATTR *full_objectid) +{ + OBJECT_ID_INDEX_KEY key; + struct OBJECT_ID_INDEX *entry; + ntfs_index_context *xo; + ntfs_inode *xoni; + int res; + + res = -1; + xo = open_object_id_index(ni->vol); + if (xo) { + memcpy(&key.object_id,objectid_attr,sizeof(GUID)); + if (!ntfs_index_lookup(&key, + sizeof(OBJECT_ID_INDEX_KEY), xo)) { + entry = (struct OBJECT_ID_INDEX*)xo->entry; + /* make sure inode numbers match */ + if (entry + && (MREF(le64_to_cpu(entry->data.file_id)) + == ni->mft_no)) { + memcpy(&full_objectid->birth_volume_id, + &entry->data.birth_volume_id, + sizeof(GUID)); + memcpy(&full_objectid->birth_object_id, + &entry->data.birth_object_id, + sizeof(GUID)); + memcpy(&full_objectid->domain_id, + &entry->data.domain_id, + sizeof(GUID)); + res = 0; + } + } + xoni = xo->ni; + ntfs_index_ctx_put(xo); + ntfs_inode_close(xoni); + } + return (res); +} + +#endif /* HAVE_SETXATTR */ + +/* + * Remove an object id index entry if attribute present + * + * Returns the size of existing object id + * (the existing object_d is returned) + * -1 if failure, explained by errno + */ + +static int remove_object_id_index(ntfs_attr *na, ntfs_index_context *xo, + OBJECT_ID_ATTR *old_attr) +{ + OBJECT_ID_INDEX_KEY key; + struct OBJECT_ID_INDEX *entry; + s64 size; + int ret; + + ret = na->data_size; + if (ret) { + /* read the existing object id attribute */ + size = ntfs_attr_pread(na, 0, sizeof(GUID), old_attr); + if (size >= (s64)sizeof(GUID)) { + memcpy(&key.object_id, + &old_attr->object_id,sizeof(GUID)); + size = sizeof(GUID); + if (!ntfs_index_lookup(&key, + sizeof(OBJECT_ID_INDEX_KEY), xo)) { + entry = (struct OBJECT_ID_INDEX*)xo->entry; + memcpy(&old_attr->birth_volume_id, + &entry->data.birth_volume_id, + sizeof(GUID)); + memcpy(&old_attr->birth_object_id, + &entry->data.birth_object_id, + sizeof(GUID)); + memcpy(&old_attr->domain_id, + &entry->data.domain_id, + sizeof(GUID)); + size = sizeof(OBJECT_ID_ATTR); + if (ntfs_index_rm(xo)) + ret = -1; + } + } else { + ret = -1; + errno = ENODATA; + } + } + return (ret); +} + +#ifdef HAVE_SETXATTR /* extended attributes interface required */ + +/* + * Update the object id and index + * + * The object_id attribute should have been created and the + * non-duplication of the GUID should have been checked before. + * + * Returns 0 if success + * -1 if failure, explained by errno + * If could not remove the existing index, nothing is done, + * If could not write the new data, no index entry is inserted + * If failed to insert the index, data is removed + */ + +static int update_object_id(ntfs_inode *ni, ntfs_index_context *xo, + const OBJECT_ID_ATTR *value, size_t size) +{ + OBJECT_ID_ATTR old_attr; + ntfs_attr *na; + int oldsize; + int written; + int res; + + res = 0; + + na = ntfs_attr_open(ni, AT_OBJECT_ID, AT_UNNAMED, 0); + if (na) { + + /* remove the existing index entry */ + oldsize = remove_object_id_index(na,xo,&old_attr); + if (oldsize < 0) + res = -1; + else { + /* resize attribute */ + res = ntfs_attr_truncate(na, (s64)sizeof(GUID)); + /* write the object_id in attribute */ + if (!res && value) { + written = (int)ntfs_attr_pwrite(na, + (s64)0, (s64)sizeof(GUID), + &value->object_id); + if (written != (s64)sizeof(GUID)) { + ntfs_log_error("Failed to update " + "object id\n"); + errno = EIO; + res = -1; + } + } + /* write index part if provided */ + if (!res + && ((size < sizeof(OBJECT_ID_ATTR)) + || set_object_id_index(ni,xo,value))) { + /* + * If cannot index, try to remove the object + * id and log the error. There will be an + * inconsistency if removal fails. + */ + ntfs_attr_rm(na); + ntfs_log_error("Failed to index object id." + " Possible corruption.\n"); + } + } + ntfs_attr_close(na); + NInoSetDirty(ni); + } else + res = -1; + return (res); +} + +/* + * Add a (dummy) object id to an inode if it does not exist + * + * returns 0 if attribute was inserted (or already present) + * -1 if adding failed (explained by errno) + */ + +static int add_object_id(ntfs_inode *ni, int flags) +{ + int res; + u8 dummy; + + res = -1; /* default return */ + if (!ntfs_attr_exist(ni,AT_OBJECT_ID, AT_UNNAMED,0)) { + if (!(flags & XATTR_REPLACE)) { + /* + * no object id attribute : add one, + * apparently, this does not feed the new value in + * Note : NTFS version must be >= 3 + */ + if (ni->vol->major_ver >= 3) { + res = ntfs_attr_add(ni, AT_OBJECT_ID, + AT_UNNAMED, 0, &dummy, (s64)0); + NInoSetDirty(ni); + } else + errno = EOPNOTSUPP; + } else + errno = ENODATA; + } else { + if (flags & XATTR_CREATE) + errno = EEXIST; + else + res = 0; + } + return (res); +} + +#endif /* HAVE_SETXATTR */ + +/* + * Delete an object_id index entry + * + * Returns 0 if success + * -1 if failure, explained by errno + */ + +int ntfs_delete_object_id_index(ntfs_inode *ni) +{ + ntfs_index_context *xo; + ntfs_inode *xoni; + ntfs_attr *na; + OBJECT_ID_ATTR old_attr; + int res; + + res = 0; + na = ntfs_attr_open(ni, AT_OBJECT_ID, AT_UNNAMED, 0); + if (na) { + /* + * read the existing object id + * and un-index it + */ + xo = open_object_id_index(ni->vol); + if (xo) { + if (remove_object_id_index(na,xo,&old_attr) < 0) + res = -1; + xoni = xo->ni; + ntfs_index_entry_mark_dirty(xo); + NInoSetDirty(xoni); + ntfs_index_ctx_put(xo); + ntfs_inode_close(xoni); + } + ntfs_attr_close(na); + } + return (res); +} + +#ifdef HAVE_SETXATTR /* extended attributes interface required */ + +/* + * Get the ntfs object id into an extended attribute + * + * If present, the object_id from the attribute and the GUIDs + * from the index are returned (formatted as OBJECT_ID_ATTR) + * + * Returns the global size (can be 0, 16 or 64) + * and the buffer is updated if it is long enough + */ + +int ntfs_get_ntfs_object_id(ntfs_inode *ni, char *value, size_t size) +{ + OBJECT_ID_ATTR full_objectid; + OBJECT_ID_ATTR *objectid_attr; + s64 attr_size; + int full_size; + + full_size = 0; /* default to no data and some error to be defined */ + if (ni) { + objectid_attr = (OBJECT_ID_ATTR*)ntfs_attr_readall(ni, + AT_OBJECT_ID,(ntfschar*)NULL, 0, &attr_size); + if (objectid_attr) { + /* restrict to only GUID present in attr */ + if (attr_size == sizeof(GUID)) { + memcpy(&full_objectid.object_id, + objectid_attr,sizeof(GUID)); + full_size = sizeof(GUID); + /* get data from index, if any */ + if (!merge_index_data(ni, objectid_attr, + &full_objectid)) { + full_size = sizeof(OBJECT_ID_ATTR); + } + if (full_size <= (s64)size) { + if (value) + memcpy(value,&full_objectid, + full_size); + else + errno = EINVAL; + } + } else { + /* unexpected size, better return unsupported */ + errno = EOPNOTSUPP; + full_size = 0; + } + free(objectid_attr); + } else + errno = ENODATA; + } + return (full_size ? (int)full_size : -errno); +} + +/* + * Set the object id from an extended attribute + * + * If the size is 64, the attribute and index are set. + * else if the size is not less than 16 only the attribute is set. + * The object id index is set accordingly. + * + * Returns 0, or -1 if there is a problem + */ + +int ntfs_set_ntfs_object_id(ntfs_inode *ni, + const char *value, size_t size, int flags) +{ + OBJECT_ID_INDEX_KEY key; + ntfs_inode *xoni; + ntfs_index_context *xo; + int res; + + res = 0; + if (ni && value && (size >= sizeof(GUID))) { + xo = open_object_id_index(ni->vol); + if (xo) { + /* make sure the GUID was not used somewhere */ + memcpy(&key.object_id, value, sizeof(GUID)); + if (ntfs_index_lookup(&key, + sizeof(OBJECT_ID_INDEX_KEY), xo)) { + ntfs_index_ctx_reinit(xo); + res = add_object_id(ni, flags); + if (!res) { + /* update value and index */ + res = update_object_id(ni,xo, + (const OBJECT_ID_ATTR*)value, + size); + } + } else { + /* GUID is present elsewhere */ + res = -1; + errno = EEXIST; + } + xoni = xo->ni; + ntfs_index_entry_mark_dirty(xo); + NInoSetDirty(xoni); + ntfs_index_ctx_put(xo); + ntfs_inode_close(xoni); + } else { + res = -1; + } + } else { + errno = EINVAL; + res = -1; + } + return (res ? -1 : 0); +} + +/* + * Remove the object id + * + * Returns 0, or -1 if there is a problem + */ + +int ntfs_remove_ntfs_object_id(ntfs_inode *ni) +{ + int res; + int olderrno; + ntfs_attr *na; + ntfs_inode *xoni; + ntfs_index_context *xo; + int oldsize; + OBJECT_ID_ATTR old_attr; + + res = 0; + if (ni) { + /* + * open and delete the object id + */ + na = ntfs_attr_open(ni, AT_OBJECT_ID, + AT_UNNAMED,0); + if (na) { + /* first remove index (old object id needed) */ + xo = open_object_id_index(ni->vol); + if (xo) { + oldsize = remove_object_id_index(na,xo, + &old_attr); + if (oldsize < 0) { + res = -1; + } else { + /* now remove attribute */ + res = ntfs_attr_rm(na); + if (res + && (oldsize > (int)sizeof(GUID))) { + /* + * If we could not remove the + * attribute, try to restore the + * index and log the error. There + * will be an inconsistency if + * the reindexing fails. + */ + set_object_id_index(ni, xo, + &old_attr); + ntfs_log_error( + "Failed to remove object id." + " Possible corruption.\n"); + } + } + + xoni = xo->ni; + ntfs_index_entry_mark_dirty(xo); + NInoSetDirty(xoni); + ntfs_index_ctx_put(xo); + ntfs_inode_close(xoni); + } + olderrno = errno; + ntfs_attr_close(na); + /* avoid errno pollution */ + if (errno == ENOENT) + errno = olderrno; + } else { + errno = ENODATA; + res = -1; + } + NInoSetDirty(ni); + } else { + errno = EINVAL; + res = -1; + } + return (res ? -1 : 0); +} + +#endif /* HAVE_SETXATTR */ diff --git a/libntfs-3g/reparse.c b/libntfs-3g/reparse.c new file mode 100755 index 0000000..0f6360e --- a/dev/null +++ b/libntfs-3g/reparse.c @@ -0,0 +1,1222 @@ +/** + * reparse.c - Processing of reparse points + * + * This module is part of ntfs-3g library + * + * Copyright (c) 2008-2009 Jean-Pierre Andre + * + * This program/include file 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/include file 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 (in the main directory of the NTFS-3G + * distribution in the file COPYING); if not, write to the Free Software + * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_ERRNO_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_SYS_STAT_H +#include +#endif + +#ifdef HAVE_SETXATTR +#include +#endif + +#ifdef HAVE_SYS_SYSMACROS_H +#include +#endif + +#include "types.h" +#include "debug.h" +#include "attrib.h" +#include "inode.h" +#include "dir.h" +#include "volume.h" +#include "mft.h" +#include "index.h" +#include "lcnalloc.h" +#include "logging.h" +#include "misc.h" +#include "reparse.h" + +/* the definitions in layout.h are wrong, we use names defined in + http://msdn.microsoft.com/en-us/library/aa365740(VS.85).aspx +*/ + +#define IO_REPARSE_TAG_DFS const_cpu_to_le32(0x8000000A) +#define IO_REPARSE_TAG_DFSR const_cpu_to_le32(0x80000012) +#define IO_REPARSE_TAG_HSM const_cpu_to_le32(0xC0000004) +#define IO_REPARSE_TAG_HSM2 const_cpu_to_le32(0x80000006) +#define IO_REPARSE_TAG_MOUNT_POINT const_cpu_to_le32(0xA0000003) +#define IO_REPARSE_TAG_SIS const_cpu_to_le32(0x80000007) +#define IO_REPARSE_TAG_SYMLINK const_cpu_to_le32(0xA000000C) + +struct MOUNT_POINT_REPARSE_DATA { /* reparse data for junctions */ + le16 subst_name_offset; + le16 subst_name_length; + le16 print_name_offset; + le16 print_name_length; + char path_buffer[0]; /* above data assume this is char array */ +} ; + +struct SYMLINK_REPARSE_DATA { /* reparse data for symlinks */ + le16 subst_name_offset; + le16 subst_name_length; + le16 print_name_offset; + le16 print_name_length; + le32 flags; /* 1 for full target, otherwise 0 */ + char path_buffer[0]; /* above data assume this is char array */ +} ; + +struct REPARSE_INDEX { /* index entry in $Extend/$Reparse */ + INDEX_ENTRY_HEADER header; + REPARSE_INDEX_KEY key; + le32 filling; +} ; + +static const ntfschar dir_junction_head[] = { + const_cpu_to_le16('\\'), + const_cpu_to_le16('?'), + const_cpu_to_le16('?'), + const_cpu_to_le16('\\') +} ; + +static const ntfschar vol_junction_head[] = { + const_cpu_to_le16('\\'), + const_cpu_to_le16('?'), + const_cpu_to_le16('?'), + const_cpu_to_le16('\\'), + const_cpu_to_le16('V'), + const_cpu_to_le16('o'), + const_cpu_to_le16('l'), + const_cpu_to_le16('u'), + const_cpu_to_le16('m'), + const_cpu_to_le16('e'), + const_cpu_to_le16('{'), +} ; + +static ntfschar reparse_index_name[] = { const_cpu_to_le16('$'), + const_cpu_to_le16('R') }; + +static const char mappingdir[] = ".NTFS-3G/"; + +/* + * Fix a file name with doubtful case in some directory index + * and return the name with the casing used in directory. + * + * Should only be used to translate paths stored with case insensitivity + * (such as directory junctions) when no case conflict is expected. + * If there some ambiguity, the name which collates first is returned. + * + * The name is converted to upper case and searched the usual way. + * The collation rules for file names are such that we should get the + * first candidate if any. + */ + +static u64 ntfs_fix_file_name(ntfs_inode *dir_ni, ntfschar *uname, + int uname_len) +{ + ntfs_volume *vol = dir_ni->vol; + ntfs_index_context *icx; + u64 mref; + le64 lemref; + int lkup; + int olderrno; + int i; + u32 cpuchar; + INDEX_ENTRY *entry; + FILE_NAME_ATTR *found; + struct { + FILE_NAME_ATTR attr; + ntfschar file_name[NTFS_MAX_NAME_LEN + 1]; + } find; + + mref = (u64)-1; /* default return (not found) */ + icx = ntfs_index_ctx_get(dir_ni, NTFS_INDEX_I30, 4); + if (icx) { + if (uname_len > NTFS_MAX_NAME_LEN) + uname_len = NTFS_MAX_NAME_LEN; + find.attr.file_name_length = uname_len; + for (i=0; iupcase_len) + && (le16_to_cpu(vol->upcase[cpuchar]) < cpuchar)) + find.attr.file_name[i] = vol->upcase[cpuchar]; + else + find.attr.file_name[i] = uname[i]; + } + olderrno = errno; + lkup = ntfs_index_lookup((char*)&find, uname_len, icx); + if (errno == ENOENT) + errno = olderrno; + /* + * We generally only get the first matching candidate, + * so we still have to check whether this is a real match + */ + if (icx->entry && (icx->entry->ie_flags & INDEX_ENTRY_END)) + /* get next entry if reaching end of block */ + entry = ntfs_index_next(icx->entry, icx); + else + entry = icx->entry; + if (entry) { + found = &entry->key.file_name; + if (lkup + && ntfs_names_are_equal(find.attr.file_name, + find.attr.file_name_length, + found->file_name, found->file_name_length, + IGNORE_CASE, + vol->upcase, vol->upcase_len)) + lkup = 0; + if (!lkup) { + /* + * name found : + * fix original name and return inode + */ + lemref = entry->indexed_file; + mref = le64_to_cpu(lemref); + for (i=0; ifile_name_length; i++) + uname[i] = found->file_name[i]; + } + } + ntfs_index_ctx_put(icx); + } + return (mref); +} + +/* + * Search for a directory junction or a symbolic link + * along the target path, with target defined as a full absolute path + * + * Returns the path translated to a Linux path + * or NULL if the path is not valid + */ + +static char *search_absolute(ntfs_volume *vol, ntfschar *path, + int count, BOOL isdir) +{ + ntfs_inode *ni; + u64 inum; + char *target; + int start; + int len; + + target = (char*)NULL; /* default return */ + ni = ntfs_inode_open(vol, (MFT_REF)FILE_root); + if (ni) { + start = 0; + do { + len = 0; + while (((start + len) < count) + && (path[start + len] != const_cpu_to_le16('\\'))) + len++; + inum = ntfs_fix_file_name(ni, &path[start], len); + ntfs_inode_close(ni); + ni = (ntfs_inode*)NULL; + if (inum != (u64)-1) { + inum = MREF(inum); + ni = ntfs_inode_open(vol, inum); + start += len; + if (start < count) + path[start++] = const_cpu_to_le16('/'); + } + } while (ni + && (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) + && (start < count)); + if (ni + && (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY ? isdir : !isdir)) + if (ntfs_ucstombs(path, count, &target, 0) < 0) { + if (target) { + free(target); + target = (char*)NULL; + } + } + if (ni) + ntfs_inode_close(ni); + } + return (target); +} + +/* + * Search for a symbolic link along the target path, + * with the target defined as a relative path + * + * Note : the path used to access the current inode, may be + * different from the one implied in the target definition, + * when an inode has names in several directories. + * + * Returns the path translated to a Linux path + * or NULL if the path is not valid + */ + +static char *search_relative(ntfs_inode *ni, ntfschar *path, int count) +{ + char *target = (char*)NULL; + ntfs_inode *curni; + ntfs_inode *newni; + u64 inum; + int pos; + int lth; + BOOL ok; + int max = 32; /* safety */ + + pos = 0; + ok = TRUE; + curni = ntfs_dir_parent_inode(ni); + while (curni && ok && (pos < (count - 1)) && --max) { + if ((count >= (pos + 2)) + && (path[pos] == const_cpu_to_le16('.')) + && (path[pos+1] == const_cpu_to_le16('\\'))) { + path[1] = const_cpu_to_le16('/'); + pos += 2; + } else { + if ((count >= (pos + 3)) + && (path[pos] == const_cpu_to_le16('.')) + &&(path[pos+1] == const_cpu_to_le16('.')) + && (path[pos+2] == const_cpu_to_le16('\\'))) { + path[2] = const_cpu_to_le16('/'); + pos += 3; + newni = ntfs_dir_parent_inode(curni); + if (curni != ni) + ntfs_inode_close(curni); + curni = newni; + if (!curni) + ok = FALSE; + } else { + lth = 0; + while (((pos + lth) < count) + && (path[pos + lth] != const_cpu_to_le16('\\'))) + lth++; + if (lth > 0) + inum = ntfs_fix_file_name(curni,&path[pos],lth); + else + inum = (u64)-1; + if (!lth + || ((curni != ni) + && ntfs_inode_close(curni)) + || (inum == (u64)-1)) + ok = FALSE; + else { + curni = ntfs_inode_open(ni->vol, MREF(inum)); + if (!curni) + ok = FALSE; + else { + if (ok && ((pos + lth) < count)) { + path[pos + lth] = const_cpu_to_le16('/'); + pos += lth + 1; + } else { + pos += lth; + if ((ni->mrec->flags ^ curni->mrec->flags) + & MFT_RECORD_IS_DIRECTORY) + ok = FALSE; + if (ntfs_inode_close(curni)) + ok = FALSE; + } + } + } + } + } + } + + if (ok && (ntfs_ucstombs(path, count, &target, 0) < 0)) { + free(target); // needed ? + target = (char*)NULL; + } + return (target); +} + +/* + * Check whether a drive letter has been defined in .NTFS-3G + * + * Returns 1 if found, + * 0 if not found, + * -1 if there was an error (described by errno) + */ + +static int ntfs_drive_letter(ntfs_volume *vol, ntfschar letter) +{ + char defines[NTFS_MAX_NAME_LEN + 5]; + char *drive; + int ret; + int sz; + int olderrno; + ntfs_inode *ni; + + ret = -1; + drive = (char*)NULL; + sz = ntfs_ucstombs(&letter, 1, &drive, 0); + if (sz > 0) { + strcpy(defines,mappingdir); + if ((*drive >= 'a') && (*drive <= 'z')) + *drive += 'A' - 'a'; + strcat(defines,drive); + strcat(defines,":"); + olderrno = errno; + ni = ntfs_pathname_to_inode(vol, NULL, defines); + if (ni && !ntfs_inode_close(ni)) + ret = 1; + else + if (errno == ENOENT) { + ret = 0; + /* avoid errno pollution */ + errno = olderrno; + } + } + if (drive) + free(drive); + return (ret); +} + +/* + * Do some sanity checks on reparse data + * + * The only general check is about the size (at least the tag must + * be present) + * If the reparse data looks like a junction point or symbolic + * link, more checks can be done. + * + */ + +static BOOL valid_reparse_data(ntfs_inode *ni, + const REPARSE_POINT *reparse_attr, size_t size) +{ + BOOL ok; + unsigned int offs; + unsigned int lth; + const struct MOUNT_POINT_REPARSE_DATA *mount_point_data; + const struct SYMLINK_REPARSE_DATA *symlink_data; + + ok = ni && reparse_attr + && (size >= sizeof(REPARSE_POINT)) + && (((size_t)le16_to_cpu(reparse_attr->reparse_data_length) + + sizeof(REPARSE_POINT)) == size); + if (ok) { + switch (reparse_attr->reparse_tag) { + case IO_REPARSE_TAG_MOUNT_POINT : + mount_point_data = (const struct MOUNT_POINT_REPARSE_DATA*) + reparse_attr->reparse_data; + offs = le16_to_cpu(mount_point_data->subst_name_offset); + lth = le16_to_cpu(mount_point_data->subst_name_length); + /* consistency checks */ + if (!(ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) + || ((size_t)((sizeof(REPARSE_POINT) + + sizeof(struct MOUNT_POINT_REPARSE_DATA) + + offs + lth)) > size)) + ok = FALSE; + break; + case IO_REPARSE_TAG_SYMLINK : + symlink_data = (const struct SYMLINK_REPARSE_DATA*) + reparse_attr->reparse_data; + offs = le16_to_cpu(symlink_data->subst_name_offset); + lth = le16_to_cpu(symlink_data->subst_name_length); + if ((size_t)((sizeof(REPARSE_POINT) + + sizeof(struct SYMLINK_REPARSE_DATA) + + offs + lth)) > size) + ok = FALSE; + break; + default : + break; + } + } + if (!ok) + errno = EINVAL; + return (ok); +} + +/* + * Check and translate the target of a junction point or + * a full absolute symbolic link. + * + * A full target definition begins with "\??\" or "\\?\" + * + * The fully defined target is redefined as a relative link, + * - either to the target if found on the same device. + * - or into the /.NTFS-3G directory for the user to define + * In the first situation, the target is translated to case-sensitive path. + * + * returns the target converted to a relative symlink + * or NULL if there were some problem, as described by errno + */ + +static char *ntfs_get_fulllink(ntfs_volume *vol, ntfschar *junction, + int count, const char *mnt_point, BOOL isdir) +{ + char *target; + char *fulltarget; + int sz; + char *q; + enum { DIR_JUNCTION, VOL_JUNCTION, NO_JUNCTION } kind; + + target = (char*)NULL; + fulltarget = (char*)NULL; + /* + * For a valid directory junction we want \??\x:\ + * where \ is an individual char and x a non-null char + */ + if ((count >= 7) + && !memcmp(junction,dir_junction_head,8) + && junction[4] + && (junction[5] == const_cpu_to_le16(':')) + && (junction[6] == const_cpu_to_le16('\\'))) + kind = DIR_JUNCTION; + else + /* + * For a valid volume junction we want \\?\Volume{ + * and a final \ (where \ is an individual char) + */ + if ((count >= 12) + && !memcmp(junction,vol_junction_head,22) + && (junction[count-1] == const_cpu_to_le16('\\'))) + kind = VOL_JUNCTION; + else + kind = NO_JUNCTION; + /* + * Directory junction with an explicit path and + * no specific definition for the drive letter : + * try to interpret as a target on the same volume + */ + if ((kind == DIR_JUNCTION) + && (count >= 7) + && junction[7] + && !ntfs_drive_letter(vol, junction[4])) { + target = search_absolute(vol,&junction[7],count - 7, isdir); + if (target) { + fulltarget = (char*)ntfs_malloc(strlen(mnt_point) + + strlen(target) + 2); + if (fulltarget) { + strcpy(fulltarget,mnt_point); + strcat(fulltarget,"/"); + strcat(fulltarget,target); + } + free(target); + } + } + /* + * Volume junctions or directory junctions with + * target not found on current volume : + * link to /.NTFS-3G/target which the user can + * define as a symbolic link to the real target + */ + if (((kind == DIR_JUNCTION) && !fulltarget) + || (kind == VOL_JUNCTION)) { + sz = ntfs_ucstombs(&junction[4], + (kind == VOL_JUNCTION ? count - 5 : count - 4), + &target, 0); + if ((sz > 0) && target) { + /* reverse slashes */ + for (q=target; *q; q++) + if (*q == '\\') + *q = '/'; + /* force uppercase drive letter */ + if ((target[1] == ':') + && (target[0] >= 'a') + && (target[0] <= 'z')) + target[0] += 'A' - 'a'; + fulltarget = (char*)ntfs_malloc(strlen(mnt_point) + + sizeof(mappingdir) + strlen(target) + 1); + if (fulltarget) { + strcpy(fulltarget,mnt_point); + strcat(fulltarget,"/"); + strcat(fulltarget,mappingdir); + strcat(fulltarget,target); + } + } + if (target) + free(target); + } + return (fulltarget); +} + +/* + * Check and translate the target of an absolute symbolic link. + * + * An absolute target definition begins with "\" or "x:\" + * + * The absolute target is redefined as a relative link, + * - either to the target if found on the same device. + * - or into the /.NTFS-3G directory for the user to define + * In the first situation, the target is translated to case-sensitive path. + * + * returns the target converted to a relative symlink + * or NULL if there were some problem, as described by errno + */ + +static char *ntfs_get_abslink(ntfs_volume *vol, ntfschar *junction, + int count, const char *mnt_point, BOOL isdir) +{ + char *target; + char *fulltarget; + int sz; + char *q; + enum { FULL_PATH, ABS_PATH, REJECTED_PATH } kind; + + target = (char*)NULL; + fulltarget = (char*)NULL; + /* + * For a full valid path we want x:\ + * where \ is an individual char and x a non-null char + */ + if ((count >= 3) + && junction[0] + && (junction[1] == const_cpu_to_le16(':')) + && (junction[2] == const_cpu_to_le16('\\'))) + kind = FULL_PATH; + else + /* + * For an absolute path we want an initial \ + */ + if ((count >= 0) + && (junction[0] == const_cpu_to_le16('\\'))) + kind = ABS_PATH; + else + kind = REJECTED_PATH; + /* + * Full path, with a drive letter and + * no specific definition for the drive letter : + * try to interpret as a target on the same volume. + * Do the same for an abs path with no drive letter. + */ + if (((kind == FULL_PATH) + && (count >= 3) + && junction[3] + && !ntfs_drive_letter(vol, junction[0])) + || (kind == ABS_PATH)) { + if (kind == ABS_PATH) + target = search_absolute(vol, &junction[1], + count - 1, isdir); + else + target = search_absolute(vol, &junction[3], + count - 3, isdir); + if (target) { + fulltarget = (char*)ntfs_malloc(strlen(mnt_point) + + strlen(target) + 2); + if (fulltarget) { + strcpy(fulltarget,mnt_point); + strcat(fulltarget,"/"); + strcat(fulltarget,target); + } + free(target); + } + } + /* + * full path with target not found on current volume : + * link to /.NTFS-3G/target which the user can + * define as a symbolic link to the real target + */ + if ((kind == FULL_PATH) && !fulltarget) { + sz = ntfs_ucstombs(&junction[0], + count,&target, 0); + if ((sz > 0) && target) { + /* reverse slashes */ + for (q=target; *q; q++) + if (*q == '\\') + *q = '/'; + /* force uppercase drive letter */ + if ((target[1] == ':') + && (target[0] >= 'a') + && (target[0] <= 'z')) + target[0] += 'A' - 'a'; + fulltarget = (char*)ntfs_malloc(strlen(mnt_point) + + sizeof(mappingdir) + strlen(target) + 1); + if (fulltarget) { + strcpy(fulltarget,mnt_point); + strcat(fulltarget,"/"); + strcat(fulltarget,mappingdir); + strcat(fulltarget,target); + } + } + if (target) + free(target); + } + return (fulltarget); +} + +/* + * Check and translate the target of a relative symbolic link. + * + * A relative target definition does not begin with "\" + * + * The original definition of relative target is kept, it is just + * translated to a case-sensitive path. + * + * returns the target converted to a relative symlink + * or NULL if there were some problem, as described by errno + */ + +static char *ntfs_get_rellink(ntfs_inode *ni, ntfschar *junction, int count) +{ + char *target; + + target = search_relative(ni,junction,count); + return (target); +} + +/* + * Get the target for a junction point or symbolic link + * Should only be called for files or directories with reparse data + * + * returns the target converted to a relative path, or NULL + * if some error occurred, as described by errno + * errno is EOPNOTSUPP if the reparse point is not a valid + * symbolic link or directory junction + */ + +char *ntfs_make_symlink(ntfs_inode *ni, const char *mnt_point, + int *pattr_size) +{ + s64 attr_size = 0; + char *target; + unsigned int offs; + unsigned int lth; + ntfs_volume *vol; + REPARSE_POINT *reparse_attr; + struct MOUNT_POINT_REPARSE_DATA *mount_point_data; + struct SYMLINK_REPARSE_DATA *symlink_data; + enum { FULL_TARGET, ABS_TARGET, REL_TARGET } kind; + ntfschar *p; + BOOL bad; + BOOL isdir; + + target = (char*)NULL; + bad = TRUE; + isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) + != const_cpu_to_le16(0); + vol = ni->vol; + reparse_attr = (REPARSE_POINT*)ntfs_attr_readall(ni, + AT_REPARSE_POINT,(ntfschar*)NULL, 0, &attr_size); + if (reparse_attr && attr_size + && valid_reparse_data(ni, reparse_attr, attr_size)) { + switch (reparse_attr->reparse_tag) { + case IO_REPARSE_TAG_MOUNT_POINT : + mount_point_data = (struct MOUNT_POINT_REPARSE_DATA*) + reparse_attr->reparse_data; + offs = le16_to_cpu(mount_point_data->subst_name_offset); + lth = le16_to_cpu(mount_point_data->subst_name_length); + /* reparse data consistency has been checked */ + target = ntfs_get_fulllink(vol, + (ntfschar*)&mount_point_data->path_buffer[offs], + lth/2, mnt_point, isdir); + if (target) + bad = FALSE; + break; + case IO_REPARSE_TAG_SYMLINK : + symlink_data = (struct SYMLINK_REPARSE_DATA*) + reparse_attr->reparse_data; + offs = le16_to_cpu(symlink_data->subst_name_offset); + lth = le16_to_cpu(symlink_data->subst_name_length); + p = (ntfschar*)&symlink_data->path_buffer[offs]; + /* + * Predetermine the kind of target, + * the called function has to make a full check + */ + if (*p++ == const_cpu_to_le16('\\')) { + if ((*p == const_cpu_to_le16('?')) + || (*p == const_cpu_to_le16('\\'))) + kind = FULL_TARGET; + else + kind = ABS_TARGET; + } else + if (*p == const_cpu_to_le16(':')) + kind = ABS_TARGET; + else + kind = REL_TARGET; + p--; + /* reparse data consistency has been checked */ + switch (kind) { + case FULL_TARGET : + if (!(symlink_data->flags + & const_cpu_to_le32(1))) { + target = ntfs_get_fulllink(vol, + p, lth/2, + mnt_point, isdir); + if (target) + bad = FALSE; + } + break; + case ABS_TARGET : + if (symlink_data->flags + & const_cpu_to_le32(1)) { + target = ntfs_get_abslink(vol, + p, lth/2, + mnt_point, isdir); + if (target) + bad = FALSE; + } + break; + case REL_TARGET : + if (symlink_data->flags + & const_cpu_to_le32(1)) { + target = ntfs_get_rellink(ni, + p, lth/2); + if (target) + bad = FALSE; + } + break; + } + break; + } + free(reparse_attr); + } + *pattr_size = attr_size; + if (bad) + errno = EOPNOTSUPP; + return (target); +} + +/* + * Check whether a reparse point looks like a junction point + * or a symbolic link. + * Should only be called for files or directories with reparse data + * + * The validity of the target is not checked. + */ + +BOOL ntfs_possible_symlink(ntfs_inode *ni) +{ + s64 attr_size = 0; + REPARSE_POINT *reparse_attr; + BOOL possible; + + possible = FALSE; + reparse_attr = (REPARSE_POINT*)ntfs_attr_readall(ni, + AT_REPARSE_POINT,(ntfschar*)NULL, 0, &attr_size); + if (reparse_attr && attr_size) { + switch (reparse_attr->reparse_tag) { + case IO_REPARSE_TAG_MOUNT_POINT : + case IO_REPARSE_TAG_SYMLINK : + possible = TRUE; + default : ; + } + free(reparse_attr); + } + return (possible); +} + +#ifdef HAVE_SETXATTR /* extended attributes interface required */ + +/* + * Set the index for new reparse data + * + * Returns 0 if success + * -1 if failure, explained by errno + */ + +static int set_reparse_index(ntfs_inode *ni, ntfs_index_context *xr, + le32 reparse_tag) +{ + struct REPARSE_INDEX indx; + u64 file_id_cpu; + le64 file_id; + le16 seqn; + + seqn = ni->mrec->sequence_number; + file_id_cpu = MK_MREF(ni->mft_no,le16_to_cpu(seqn)); + file_id = cpu_to_le64(file_id_cpu); + indx.header.data_offset = const_cpu_to_le16( + sizeof(INDEX_ENTRY_HEADER) + + sizeof(REPARSE_INDEX_KEY)); + indx.header.data_length = const_cpu_to_le16(0); + indx.header.reservedV = const_cpu_to_le32(0); + indx.header.length = const_cpu_to_le16( + sizeof(struct REPARSE_INDEX)); + indx.header.key_length = const_cpu_to_le16( + sizeof(REPARSE_INDEX_KEY)); + indx.header.flags = const_cpu_to_le16(0); + indx.header.reserved = const_cpu_to_le16(0); + indx.key.reparse_tag = reparse_tag; + /* danger on processors which require proper alignment ! */ + memcpy(&indx.key.file_id, &file_id, 8); + indx.filling = const_cpu_to_le32(0); + ntfs_index_ctx_reinit(xr); + return (ntfs_ie_add(xr,(INDEX_ENTRY*)&indx)); +} + +#endif /* HAVE_SETXATTR */ + +/* + * Remove a reparse data index entry if attribute present + * + * Returns the size of existing reparse data + * (the existing reparse tag is returned) + * -1 if failure, explained by errno + */ + +static int remove_reparse_index(ntfs_attr *na, ntfs_index_context *xr, + le32 *preparse_tag) +{ + REPARSE_INDEX_KEY key; + u64 file_id_cpu; + le64 file_id; + s64 size; + le16 seqn; + int ret; + + ret = na->data_size; + if (ret) { + /* read the existing reparse_tag */ + size = ntfs_attr_pread(na, 0, 4, preparse_tag); + if (size == 4) { + seqn = na->ni->mrec->sequence_number; + file_id_cpu = MK_MREF(na->ni->mft_no,le16_to_cpu(seqn)); + file_id = cpu_to_le64(file_id_cpu); + key.reparse_tag = *preparse_tag; + /* danger on processors which require proper alignment ! */ + memcpy(&key.file_id, &file_id, 8); + if (!ntfs_index_lookup(&key, sizeof(REPARSE_INDEX_KEY), xr) + && ntfs_index_rm(xr)) + ret = -1; + } else { + ret = -1; + errno = ENODATA; + } + } + return (ret); +} + +/* + * Open the $Extend/$Reparse file and its index + * + * Return the index context if opened + * or NULL if an error occurred (errno tells why) + * + * The index has to be freed and inode closed when not needed any more. + */ + +static ntfs_index_context *open_reparse_index(ntfs_volume *vol) +{ + u64 inum; + ntfs_inode *ni; + ntfs_inode *dir_ni; + ntfs_index_context *xr; + + /* do not use path_name_to inode - could reopen root */ + dir_ni = ntfs_inode_open(vol, FILE_Extend); + ni = (ntfs_inode*)NULL; + if (dir_ni) { + inum = ntfs_inode_lookup_by_mbsname(dir_ni,"$Reparse"); + if (inum != (u64)-1) + ni = ntfs_inode_open(vol, inum); + ntfs_inode_close(dir_ni); + } + if (ni) { + xr = ntfs_index_ctx_get(ni, reparse_index_name, 2); + if (!xr) { + ntfs_inode_close(ni); + } + } else + xr = (ntfs_index_context*)NULL; + return (xr); +} + +#ifdef HAVE_SETXATTR /* extended attributes interface required */ + +/* + * Update the reparse data and index + * + * The reparse data attribute should have been created, and + * an existing index is expected if there is an existing value. + * + * Returns 0 if success + * -1 if failure, explained by errno + * If could not remove the existing index, nothing is done, + * If could not write the new data, no index entry is inserted + * If failed to insert the index, data is removed + */ + +static int update_reparse_data(ntfs_inode *ni, ntfs_index_context *xr, + const char *value, size_t size) +{ + int res; + int written; + int oldsize; + ntfs_attr *na; + le32 reparse_tag; + + res = 0; + na = ntfs_attr_open(ni, AT_REPARSE_POINT, AT_UNNAMED, 0); + if (na) { + /* remove the existing reparse data */ + oldsize = remove_reparse_index(na,xr,&reparse_tag); + if (oldsize < 0) + res = -1; + else { + /* resize attribute */ + res = ntfs_attr_truncate(na, (s64)size); + /* overwrite value if any */ + if (!res && value) { + written = (int)ntfs_attr_pwrite(na, + (s64)0, (s64)size, value); + if (written != (s64)size) { + ntfs_log_error("Failed to update " + "reparse data\n"); + errno = EIO; + res = -1; + } + } + if (!res + && set_reparse_index(ni,xr, + ((const REPARSE_POINT*)value)->reparse_tag) + && (oldsize > 0)) { + /* + * If cannot index, try to remove the reparse + * data and log the error. There will be an + * inconsistency if removal fails. + */ + ntfs_attr_rm(na); + ntfs_log_error("Failed to index reparse data." + " Possible corruption.\n"); + } + } + ntfs_attr_close(na); + NInoSetDirty(ni); + } else + res = -1; + return (res); +} + +#endif /* HAVE_SETXATTR */ + +/* + * Delete a reparse index entry + * + * Returns 0 if success + * -1 if failure, explained by errno + */ + +int ntfs_delete_reparse_index(ntfs_inode *ni) +{ + ntfs_index_context *xr; + ntfs_inode *xrni; + ntfs_attr *na; + le32 reparse_tag; + int res; + + res = 0; + na = ntfs_attr_open(ni, AT_REPARSE_POINT, AT_UNNAMED, 0); + if (na) { + /* + * read the existing reparse data (the tag is enough) + * and un-index it + */ + xr = open_reparse_index(ni->vol); + if (xr) { + if (remove_reparse_index(na,xr,&reparse_tag) < 0) + res = -1; + xrni = xr->ni; + ntfs_index_entry_mark_dirty(xr); + NInoSetDirty(xrni); + ntfs_index_ctx_put(xr); + ntfs_inode_close(xrni); + } + ntfs_attr_close(na); + } + return (res); +} + +#ifdef HAVE_SETXATTR /* extended attributes interface required */ + +/* + * Get the ntfs reparse data into an extended attribute + * + * Returns the reparse data size + * and the buffer is updated if it is long enough + */ + +int ntfs_get_ntfs_reparse_data(ntfs_inode *ni, char *value, size_t size) +{ + REPARSE_POINT *reparse_attr; + s64 attr_size; + + attr_size = 0; /* default to no data and no error */ + if (ni) { + if (ni->flags & FILE_ATTR_REPARSE_POINT) { + reparse_attr = (REPARSE_POINT*)ntfs_attr_readall(ni, + AT_REPARSE_POINT,(ntfschar*)NULL, 0, &attr_size); + if (reparse_attr) { + if (attr_size <= (s64)size) { + if (value) + memcpy(value,reparse_attr, + attr_size); + else + errno = EINVAL; + } + free(reparse_attr); + } + } else + errno = ENODATA; + } + return (attr_size ? (int)attr_size : -errno); +} + +/* + * Set the reparse data from an extended attribute + * + * Warning : the new data is not checked + * + * Returns 0, or -1 if there is a problem + */ + +int ntfs_set_ntfs_reparse_data(ntfs_inode *ni, + const char *value, size_t size, int flags) +{ + int res; + u8 dummy; + ntfs_inode *xrni; + ntfs_index_context *xr; + + res = 0; + if (ni && valid_reparse_data(ni, (const REPARSE_POINT*)value, size)) { + xr = open_reparse_index(ni->vol); + if (xr) { + if (!ntfs_attr_exist(ni,AT_REPARSE_POINT, + AT_UNNAMED,0)) { + if (!(flags & XATTR_REPLACE)) { + /* + * no reparse data attribute : add one, + * apparently, this does not feed the new value in + * Note : NTFS version must be >= 3 + */ + if (ni->vol->major_ver >= 3) { + res = ntfs_attr_add(ni, + AT_REPARSE_POINT, + AT_UNNAMED,0,&dummy, + (s64)0); + if (!res) { + ni->flags |= + FILE_ATTR_REPARSE_POINT; + NInoFileNameSetDirty(ni); + } + NInoSetDirty(ni); + } else { + errno = EOPNOTSUPP; + res = -1; + } + } else { + errno = ENODATA; + res = -1; + } + } else { + if (flags & XATTR_CREATE) { + errno = EEXIST; + res = -1; + } + } + if (!res) { + /* update value and index */ + res = update_reparse_data(ni,xr,value,size); + } + xrni = xr->ni; + ntfs_index_entry_mark_dirty(xr); + NInoSetDirty(xrni); + ntfs_index_ctx_put(xr); + ntfs_inode_close(xrni); + } else { + res = -1; + } + } else { + errno = EINVAL; + res = -1; + } + return (res ? -1 : 0); +} + +/* + * Remove the reparse data + * + * Returns 0, or -1 if there is a problem + */ + +int ntfs_remove_ntfs_reparse_data(ntfs_inode *ni) +{ + int res; + int olderrno; + ntfs_attr *na; + ntfs_inode *xrni; + ntfs_index_context *xr; + le32 reparse_tag; + + res = 0; + if (ni) { + /* + * open and delete the reparse data + */ + na = ntfs_attr_open(ni, AT_REPARSE_POINT, + AT_UNNAMED,0); + if (na) { + /* first remove index (reparse data needed) */ + xr = open_reparse_index(ni->vol); + if (xr) { + if (remove_reparse_index(na,xr, + &reparse_tag) < 0) { + res = -1; + } else { + /* now remove attribute */ + res = ntfs_attr_rm(na); + if (!res) { + ni->flags &= + ~FILE_ATTR_REPARSE_POINT; + NInoFileNameSetDirty(ni); + } else { + /* + * If we could not remove the + * attribute, try to restore the + * index and log the error. There + * will be an inconsistency if + * the reindexing fails. + */ + set_reparse_index(ni, xr, + reparse_tag); + ntfs_log_error( + "Failed to remove reparse data." + " Possible corruption.\n"); + } + } + xrni = xr->ni; + ntfs_index_entry_mark_dirty(xr); + NInoSetDirty(xrni); + ntfs_index_ctx_put(xr); + ntfs_inode_close(xrni); + } + olderrno = errno; + ntfs_attr_close(na); + /* avoid errno pollution */ + if (errno == ENOENT) + errno = olderrno; + } else { + errno = ENODATA; + res = -1; + } + NInoSetDirty(ni); + } else { + errno = EINVAL; + res = -1; + } + return (res ? -1 : 0); +} + +#endif /* HAVE_SETXATTR */ diff --git a/libntfs-3g/runlist.c b/libntfs-3g/runlist.c new file mode 100755 index 0000000..6c99e8e --- a/dev/null +++ b/libntfs-3g/runlist.c @@ -0,0 +1,2166 @@ +/** + * runlist.c - Run list handling code. Originated from the Linux-NTFS project. + * + * Copyright (c) 2002-2005 Anton Altaparmakov + * Copyright (c) 2002-2005 Richard Russon + * Copyright (c) 2002-2008 Szabolcs Szakacsits + * Copyright (c) 2004 Yura Pakhuchiy + * Copyright (c) 2007-2009 Jean-Pierre Andre + * + * This program/include file 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/include file 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 (in the main directory of the NTFS-3G + * distribution in the file COPYING); if not, write to the Free Software + * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_STDIO_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_ERRNO_H +#include +#endif + +#include "compat.h" +#include "types.h" +#include "volume.h" +#include "layout.h" +#include "debug.h" +#include "device.h" +#include "logging.h" +#include "misc.h" + +/** + * ntfs_rl_mm - runlist memmove + * @base: + * @dst: + * @src: + * @size: + * + * Description... + * + * Returns: + */ +static void ntfs_rl_mm(runlist_element *base, int dst, int src, int size) +{ + if ((dst != src) && (size > 0)) + memmove(base + dst, base + src, size * sizeof(*base)); +} + +/** + * ntfs_rl_mc - runlist memory copy + * @dstbase: + * @dst: + * @srcbase: + * @src: + * @size: + * + * Description... + * + * Returns: + */ +static void ntfs_rl_mc(runlist_element *dstbase, int dst, + runlist_element *srcbase, int src, int size) +{ + if (size > 0) + memcpy(dstbase + dst, srcbase + src, size * sizeof(*dstbase)); +} + +/** + * ntfs_rl_realloc - Reallocate memory for runlists + * @rl: original runlist + * @old_size: number of runlist elements in the original runlist @rl + * @new_size: number of runlist elements we need space for + * + * As the runlists grow, more memory will be required. To prevent large + * numbers of small reallocations of memory, this function returns a 4kiB block + * of memory. + * + * N.B. If the new allocation doesn't require a different number of 4kiB + * blocks in memory, the function will return the original pointer. + * + * On success, return a pointer to the newly allocated, or recycled, memory. + * On error, return NULL with errno set to the error code. + */ +static runlist_element *ntfs_rl_realloc(runlist_element *rl, int old_size, + int new_size) +{ + old_size = (old_size * sizeof(runlist_element) + 0xfff) & ~0xfff; + new_size = (new_size * sizeof(runlist_element) + 0xfff) & ~0xfff; + if (old_size == new_size) + return rl; + return realloc(rl, new_size); +} + +/* + * Extend a runlist by some entry count + * The runlist may have to be reallocated + * + * Returns the reallocated runlist + * or NULL if reallocation was not possible (with errno set) + */ + +runlist_element *ntfs_rl_extend(runlist_element *rl, int more_entries) +{ + int last; + + last = 0; + while (rl[last].length) + last++; + rl = ntfs_rl_realloc(rl,last+1,last+more_entries+1); + if (!rl) + errno = ENOMEM; + return (rl); +} + +/** + * ntfs_rl_are_mergeable - test if two runlists can be joined together + * @dst: original runlist + * @src: new runlist to test for mergeability with @dst + * + * Test if two runlists can be joined together. For this, their VCNs and LCNs + * must be adjacent. + * + * Return: TRUE Success, the runlists can be merged. + * FALSE Failure, the runlists cannot be merged. + */ +static BOOL ntfs_rl_are_mergeable(runlist_element *dst, runlist_element *src) +{ + if (!dst || !src) { + ntfs_log_debug("Eeek. ntfs_rl_are_mergeable() invoked with NULL " + "pointer!\n"); + return FALSE; + } + + /* We can merge unmapped regions even if they are misaligned. */ + if ((dst->lcn == LCN_RL_NOT_MAPPED) && (src->lcn == LCN_RL_NOT_MAPPED)) + return TRUE; + /* If the runs are misaligned, we cannot merge them. */ + if ((dst->vcn + dst->length) != src->vcn) + return FALSE; + /* If both runs are non-sparse and contiguous, we can merge them. */ + if ((dst->lcn >= 0) && (src->lcn >= 0) && + ((dst->lcn + dst->length) == src->lcn)) + return TRUE; + /* If we are merging two holes, we can merge them. */ + if ((dst->lcn == LCN_HOLE) && (src->lcn == LCN_HOLE)) + return TRUE; + /* Cannot merge. */ + return FALSE; +} + +/** + * __ntfs_rl_merge - merge two runlists without testing if they can be merged + * @dst: original, destination runlist + * @src: new runlist to merge with @dst + * + * Merge the two runlists, writing into the destination runlist @dst. The + * caller must make sure the runlists can be merged or this will corrupt the + * destination runlist. + */ +static void __ntfs_rl_merge(runlist_element *dst, runlist_element *src) +{ + dst->length += src->length; +} + +/** + * ntfs_rl_append - append a runlist after a given element + * @dst: original runlist to be worked on + * @dsize: number of elements in @dst (including end marker) + * @src: runlist to be inserted into @dst + * @ssize: number of elements in @src (excluding end marker) + * @loc: append the new runlist @src after this element in @dst + * + * Append the runlist @src after element @loc in @dst. Merge the right end of + * the new runlist, if necessary. Adjust the size of the hole before the + * appended runlist. + * + * On success, return a pointer to the new, combined, runlist. Note, both + * runlists @dst and @src are deallocated before returning so you cannot use + * the pointers for anything any more. (Strictly speaking the returned runlist + * may be the same as @dst but this is irrelevant.) + * + * On error, return NULL, with errno set to the error code. Both runlists are + * left unmodified. + */ +static runlist_element *ntfs_rl_append(runlist_element *dst, int dsize, + runlist_element *src, int ssize, int loc) +{ + BOOL right = FALSE; /* Right end of @src needs merging */ + int marker; /* End of the inserted runs */ + + if (!dst || !src) { + ntfs_log_debug("Eeek. ntfs_rl_append() invoked with NULL " + "pointer!\n"); + errno = EINVAL; + return NULL; + } + + /* First, check if the right hand end needs merging. */ + if ((loc + 1) < dsize) + right = ntfs_rl_are_mergeable(src + ssize - 1, dst + loc + 1); + + /* Space required: @dst size + @src size, less one if we merged. */ + dst = ntfs_rl_realloc(dst, dsize, dsize + ssize - right); + if (!dst) + return NULL; + /* + * We are guaranteed to succeed from here so can start modifying the + * original runlists. + */ + + /* First, merge the right hand end, if necessary. */ + if (right) + __ntfs_rl_merge(src + ssize - 1, dst + loc + 1); + + /* marker - First run after the @src runs that have been inserted */ + marker = loc + ssize + 1; + + /* Move the tail of @dst out of the way, then copy in @src. */ + ntfs_rl_mm(dst, marker, loc + 1 + right, dsize - loc - 1 - right); + ntfs_rl_mc(dst, loc + 1, src, 0, ssize); + + /* Adjust the size of the preceding hole. */ + dst[loc].length = dst[loc + 1].vcn - dst[loc].vcn; + + /* We may have changed the length of the file, so fix the end marker */ + if (dst[marker].lcn == LCN_ENOENT) + dst[marker].vcn = dst[marker-1].vcn + dst[marker-1].length; + + return dst; +} + +/** + * ntfs_rl_insert - insert a runlist into another + * @dst: original runlist to be worked on + * @dsize: number of elements in @dst (including end marker) + * @src: new runlist to be inserted + * @ssize: number of elements in @src (excluding end marker) + * @loc: insert the new runlist @src before this element in @dst + * + * Insert the runlist @src before element @loc in the runlist @dst. Merge the + * left end of the new runlist, if necessary. Adjust the size of the hole + * after the inserted runlist. + * + * On success, return a pointer to the new, combined, runlist. Note, both + * runlists @dst and @src are deallocated before returning so you cannot use + * the pointers for anything any more. (Strictly speaking the returned runlist + * may be the same as @dst but this is irrelevant.) + * + * On error, return NULL, with errno set to the error code. Both runlists are + * left unmodified. + */ +static runlist_element *ntfs_rl_insert(runlist_element *dst, int dsize, + runlist_element *src, int ssize, int loc) +{ + BOOL left = FALSE; /* Left end of @src needs merging */ + BOOL disc = FALSE; /* Discontinuity between @dst and @src */ + int marker; /* End of the inserted runs */ + + if (!dst || !src) { + ntfs_log_debug("Eeek. ntfs_rl_insert() invoked with NULL " + "pointer!\n"); + errno = EINVAL; + return NULL; + } + + /* disc => Discontinuity between the end of @dst and the start of @src. + * This means we might need to insert a "notmapped" run. + */ + if (loc == 0) + disc = (src[0].vcn > 0); + else { + s64 merged_length; + + left = ntfs_rl_are_mergeable(dst + loc - 1, src); + + merged_length = dst[loc - 1].length; + if (left) + merged_length += src->length; + + disc = (src[0].vcn > dst[loc - 1].vcn + merged_length); + } + + /* Space required: @dst size + @src size, less one if we merged, plus + * one if there was a discontinuity. + */ + dst = ntfs_rl_realloc(dst, dsize, dsize + ssize - left + disc); + if (!dst) + return NULL; + /* + * We are guaranteed to succeed from here so can start modifying the + * original runlist. + */ + + if (left) + __ntfs_rl_merge(dst + loc - 1, src); + + /* + * marker - First run after the @src runs that have been inserted + * Nominally: marker = @loc + @ssize (location + number of runs in @src) + * If "left", then the first run in @src has been merged with one in @dst. + * If "disc", then @dst and @src don't meet and we need an extra run to fill the gap. + */ + marker = loc + ssize - left + disc; + + /* Move the tail of @dst out of the way, then copy in @src. */ + ntfs_rl_mm(dst, marker, loc, dsize - loc); + ntfs_rl_mc(dst, loc + disc, src, left, ssize - left); + + /* Adjust the VCN of the first run after the insertion ... */ + dst[marker].vcn = dst[marker - 1].vcn + dst[marker - 1].length; + /* ... and the length. */ + if (dst[marker].lcn == LCN_HOLE || dst[marker].lcn == LCN_RL_NOT_MAPPED) + dst[marker].length = dst[marker + 1].vcn - dst[marker].vcn; + + /* Writing beyond the end of the file and there's a discontinuity. */ + if (disc) { + if (loc > 0) { + dst[loc].vcn = dst[loc - 1].vcn + dst[loc - 1].length; + dst[loc].length = dst[loc + 1].vcn - dst[loc].vcn; + } else { + dst[loc].vcn = 0; + dst[loc].length = dst[loc + 1].vcn; + } + dst[loc].lcn = LCN_RL_NOT_MAPPED; + } + return dst; +} + +/** + * ntfs_rl_replace - overwrite a runlist element with another runlist + * @dst: original runlist to be worked on + * @dsize: number of elements in @dst (including end marker) + * @src: new runlist to be inserted + * @ssize: number of elements in @src (excluding end marker) + * @loc: index in runlist @dst to overwrite with @src + * + * Replace the runlist element @dst at @loc with @src. Merge the left and + * right ends of the inserted runlist, if necessary. + * + * On success, return a pointer to the new, combined, runlist. Note, both + * runlists @dst and @src are deallocated before returning so you cannot use + * the pointers for anything any more. (Strictly speaking the returned runlist + * may be the same as @dst but this is irrelevant.) + * + * On error, return NULL, with errno set to the error code. Both runlists are + * left unmodified. + */ +static runlist_element *ntfs_rl_replace(runlist_element *dst, int dsize, + runlist_element *src, int ssize, + int loc) +{ + signed delta; + BOOL left = FALSE; /* Left end of @src needs merging */ + BOOL right = FALSE; /* Right end of @src needs merging */ + int tail; /* Start of tail of @dst */ + int marker; /* End of the inserted runs */ + + if (!dst || !src) { + ntfs_log_debug("Eeek. ntfs_rl_replace() invoked with NULL " + "pointer!\n"); + errno = EINVAL; + return NULL; + } + + /* First, see if the left and right ends need merging. */ + if ((loc + 1) < dsize) + right = ntfs_rl_are_mergeable(src + ssize - 1, dst + loc + 1); + if (loc > 0) + left = ntfs_rl_are_mergeable(dst + loc - 1, src); + + /* Allocate some space. We'll need less if the left, right, or both + * ends get merged. The -1 accounts for the run being replaced. + */ + delta = ssize - 1 - left - right; + if (delta > 0) { + dst = ntfs_rl_realloc(dst, dsize, dsize + delta); + if (!dst) + return NULL; + } + /* + * We are guaranteed to succeed from here so can start modifying the + * original runlists. + */ + + /* First, merge the left and right ends, if necessary. */ + if (right) + __ntfs_rl_merge(src + ssize - 1, dst + loc + 1); + if (left) + __ntfs_rl_merge(dst + loc - 1, src); + + /* + * tail - Offset of the tail of @dst + * Nominally: @tail = @loc + 1 (location, skipping the replaced run) + * If "right", then one of @dst's runs is already merged into @src. + */ + tail = loc + right + 1; + + /* + * marker - First run after the @src runs that have been inserted + * Nominally: @marker = @loc + @ssize (location + number of runs in @src) + * If "left", then the first run in @src has been merged with one in @dst. + */ + marker = loc + ssize - left; + + /* Move the tail of @dst out of the way, then copy in @src. */ + ntfs_rl_mm(dst, marker, tail, dsize - tail); + ntfs_rl_mc(dst, loc, src, left, ssize - left); + + /* We may have changed the length of the file, so fix the end marker */ + if (((dsize - tail) > 0) && (dst[marker].lcn == LCN_ENOENT)) + dst[marker].vcn = dst[marker - 1].vcn + dst[marker - 1].length; + + return dst; +} + +/** + * ntfs_rl_split - insert a runlist into the centre of a hole + * @dst: original runlist to be worked on + * @dsize: number of elements in @dst (including end marker) + * @src: new runlist to be inserted + * @ssize: number of elements in @src (excluding end marker) + * @loc: index in runlist @dst at which to split and insert @src + * + * Split the runlist @dst at @loc into two and insert @new in between the two + * fragments. No merging of runlists is necessary. Adjust the size of the + * holes either side. + * + * On success, return a pointer to the new, combined, runlist. Note, both + * runlists @dst and @src are deallocated before returning so you cannot use + * the pointers for anything any more. (Strictly speaking the returned runlist + * may be the same as @dst but this is irrelevant.) + * + * On error, return NULL, with errno set to the error code. Both runlists are + * left unmodified. + */ +static runlist_element *ntfs_rl_split(runlist_element *dst, int dsize, + runlist_element *src, int ssize, int loc) +{ + if (!dst || !src) { + ntfs_log_debug("Eeek. ntfs_rl_split() invoked with NULL pointer!\n"); + errno = EINVAL; + return NULL; + } + + /* Space required: @dst size + @src size + one new hole. */ + dst = ntfs_rl_realloc(dst, dsize, dsize + ssize + 1); + if (!dst) + return dst; + /* + * We are guaranteed to succeed from here so can start modifying the + * original runlists. + */ + + /* Move the tail of @dst out of the way, then copy in @src. */ + ntfs_rl_mm(dst, loc + 1 + ssize, loc, dsize - loc); + ntfs_rl_mc(dst, loc + 1, src, 0, ssize); + + /* Adjust the size of the holes either size of @src. */ + dst[loc].length = dst[loc+1].vcn - dst[loc].vcn; + dst[loc+ssize+1].vcn = dst[loc+ssize].vcn + dst[loc+ssize].length; + dst[loc+ssize+1].length = dst[loc+ssize+2].vcn - dst[loc+ssize+1].vcn; + + return dst; +} + + +/** + * ntfs_runlists_merge_i - see ntfs_runlists_merge + */ +static runlist_element *ntfs_runlists_merge_i(runlist_element *drl, + runlist_element *srl) +{ + int di, si; /* Current index into @[ds]rl. */ + int sstart; /* First index with lcn > LCN_RL_NOT_MAPPED. */ + int dins; /* Index into @drl at which to insert @srl. */ + int dend, send; /* Last index into @[ds]rl. */ + int dfinal, sfinal; /* The last index into @[ds]rl with + lcn >= LCN_HOLE. */ + int marker = 0; + VCN marker_vcn = 0; + + ntfs_log_debug("dst:\n"); + ntfs_debug_runlist_dump(drl); + ntfs_log_debug("src:\n"); + ntfs_debug_runlist_dump(srl); + + /* Check for silly calling... */ + if (!srl) + return drl; + + /* Check for the case where the first mapping is being done now. */ + if (!drl) { + drl = srl; + /* Complete the source runlist if necessary. */ + if (drl[0].vcn) { + /* Scan to the end of the source runlist. */ + for (dend = 0; drl[dend].length; dend++) + ; + dend++; + drl = ntfs_rl_realloc(drl, dend, dend + 1); + if (!drl) + return drl; + /* Insert start element at the front of the runlist. */ + ntfs_rl_mm(drl, 1, 0, dend); + drl[0].vcn = 0; + drl[0].lcn = LCN_RL_NOT_MAPPED; + drl[0].length = drl[1].vcn; + } + goto finished; + } + + si = di = 0; + + /* Skip any unmapped start element(s) in the source runlist. */ + while (srl[si].length && srl[si].lcn < (LCN)LCN_HOLE) + si++; + + /* Can't have an entirely unmapped source runlist. */ + if (!srl[si].length) { + errno = EINVAL; + ntfs_log_perror("%s: unmapped source runlist", __FUNCTION__); + return NULL; + } + + /* Record the starting points. */ + sstart = si; + + /* + * Skip forward in @drl until we reach the position where @srl needs to + * be inserted. If we reach the end of @drl, @srl just needs to be + * appended to @drl. + */ + for (; drl[di].length; di++) { + if (drl[di].vcn + drl[di].length > srl[sstart].vcn) + break; + } + dins = di; + + /* Sanity check for illegal overlaps. */ + if ((drl[di].vcn == srl[si].vcn) && (drl[di].lcn >= 0) && + (srl[si].lcn >= 0)) { + errno = ERANGE; + ntfs_log_perror("Run lists overlap. Cannot merge"); + return NULL; + } + + /* Scan to the end of both runlists in order to know their sizes. */ + for (send = si; srl[send].length; send++) + ; + for (dend = di; drl[dend].length; dend++) + ; + + if (srl[send].lcn == (LCN)LCN_ENOENT) + marker_vcn = srl[marker = send].vcn; + + /* Scan to the last element with lcn >= LCN_HOLE. */ + for (sfinal = send; sfinal >= 0 && srl[sfinal].lcn < LCN_HOLE; sfinal--) + ; + for (dfinal = dend; dfinal >= 0 && drl[dfinal].lcn < LCN_HOLE; dfinal--) + ; + + { + BOOL start; + BOOL finish; + int ds = dend + 1; /* Number of elements in drl & srl */ + int ss = sfinal - sstart + 1; + + start = ((drl[dins].lcn < LCN_RL_NOT_MAPPED) || /* End of file */ + (drl[dins].vcn == srl[sstart].vcn)); /* Start of hole */ + finish = ((drl[dins].lcn >= LCN_RL_NOT_MAPPED) && /* End of file */ + ((drl[dins].vcn + drl[dins].length) <= /* End of hole */ + (srl[send - 1].vcn + srl[send - 1].length))); + + /* Or we'll lose an end marker */ + if (finish && !drl[dins].length) + ss++; + if (marker && (drl[dins].vcn + drl[dins].length > srl[send - 1].vcn)) + finish = FALSE; + + ntfs_log_debug("dfinal = %i, dend = %i\n", dfinal, dend); + ntfs_log_debug("sstart = %i, sfinal = %i, send = %i\n", sstart, sfinal, send); + ntfs_log_debug("start = %i, finish = %i\n", start, finish); + ntfs_log_debug("ds = %i, ss = %i, dins = %i\n", ds, ss, dins); + + if (start) { + if (finish) + drl = ntfs_rl_replace(drl, ds, srl + sstart, ss, dins); + else + drl = ntfs_rl_insert(drl, ds, srl + sstart, ss, dins); + } else { + if (finish) + drl = ntfs_rl_append(drl, ds, srl + sstart, ss, dins); + else + drl = ntfs_rl_split(drl, ds, srl + sstart, ss, dins); + } + if (!drl) { + ntfs_log_perror("Merge failed"); + return drl; + } + free(srl); + if (marker) { + ntfs_log_debug("Triggering marker code.\n"); + for (ds = dend; drl[ds].length; ds++) + ; + /* We only need to care if @srl ended after @drl. */ + if (drl[ds].vcn <= marker_vcn) { + int slots = 0; + + if (drl[ds].vcn == marker_vcn) { + ntfs_log_debug("Old marker = %lli, replacing with " + "LCN_ENOENT.\n", + (long long)drl[ds].lcn); + drl[ds].lcn = (LCN)LCN_ENOENT; + goto finished; + } + /* + * We need to create an unmapped runlist element in + * @drl or extend an existing one before adding the + * ENOENT terminator. + */ + if (drl[ds].lcn == (LCN)LCN_ENOENT) { + ds--; + slots = 1; + } + if (drl[ds].lcn != (LCN)LCN_RL_NOT_MAPPED) { + /* Add an unmapped runlist element. */ + if (!slots) { + /* FIXME/TODO: We need to have the + * extra memory already! (AIA) + */ + drl = ntfs_rl_realloc(drl, ds, ds + 2); + if (!drl) + goto critical_error; + slots = 2; + } + ds++; + /* Need to set vcn if it isn't set already. */ + if (slots != 1) + drl[ds].vcn = drl[ds - 1].vcn + + drl[ds - 1].length; + drl[ds].lcn = (LCN)LCN_RL_NOT_MAPPED; + /* We now used up a slot. */ + slots--; + } + drl[ds].length = marker_vcn - drl[ds].vcn; + /* Finally add the ENOENT terminator. */ + ds++; + if (!slots) { + /* FIXME/TODO: We need to have the extra + * memory already! (AIA) + */ + drl = ntfs_rl_realloc(drl, ds, ds + 1); + if (!drl) + goto critical_error; + } + drl[ds].vcn = marker_vcn; + drl[ds].lcn = (LCN)LCN_ENOENT; + drl[ds].length = (s64)0; + } + } + } + +finished: + /* The merge was completed successfully. */ + ntfs_log_debug("Merged runlist:\n"); + ntfs_debug_runlist_dump(drl); + return drl; + +critical_error: + /* Critical error! We cannot afford to fail here. */ + ntfs_log_perror("libntfs: Critical error"); + ntfs_log_debug("Forcing segmentation fault!\n"); + marker_vcn = ((runlist*)NULL)->lcn; + return drl; +} + +/** + * ntfs_runlists_merge - merge two runlists into one + * @drl: original runlist to be worked on + * @srl: new runlist to be merged into @drl + * + * First we sanity check the two runlists @srl and @drl to make sure that they + * are sensible and can be merged. The runlist @srl must be either after the + * runlist @drl or completely within a hole (or unmapped region) in @drl. + * + * Merging of runlists is necessary in two cases: + * 1. When attribute lists are used and a further extent is being mapped. + * 2. When new clusters are allocated to fill a hole or extend a file. + * + * There are four possible ways @srl can be merged. It can: + * - be inserted at the beginning of a hole, + * - split the hole in two and be inserted between the two fragments, + * - be appended at the end of a hole, or it can + * - replace the whole hole. + * It can also be appended to the end of the runlist, which is just a variant + * of the insert case. + * + * On success, return a pointer to the new, combined, runlist. Note, both + * runlists @drl and @srl are deallocated before returning so you cannot use + * the pointers for anything any more. (Strictly speaking the returned runlist + * may be the same as @dst but this is irrelevant.) + * + * On error, return NULL, with errno set to the error code. Both runlists are + * left unmodified. The following error codes are defined: + * ENOMEM Not enough memory to allocate runlist array. + * EINVAL Invalid parameters were passed in. + * ERANGE The runlists overlap and cannot be merged. + */ +runlist_element *ntfs_runlists_merge(runlist_element *drl, + runlist_element *srl) +{ + runlist_element *rl; + + ntfs_log_enter("Entering\n"); + rl = ntfs_runlists_merge_i(drl, srl); + ntfs_log_leave("\n"); + return rl; +} + +/** + * ntfs_mapping_pairs_decompress - convert mapping pairs array to runlist + * @vol: ntfs volume on which the attribute resides + * @attr: attribute record whose mapping pairs array to decompress + * @old_rl: optional runlist in which to insert @attr's runlist + * + * Decompress the attribute @attr's mapping pairs array into a runlist. On + * success, return the decompressed runlist. + * + * If @old_rl is not NULL, decompressed runlist is inserted into the + * appropriate place in @old_rl and the resultant, combined runlist is + * returned. The original @old_rl is deallocated. + * + * On error, return NULL with errno set to the error code. @old_rl is left + * unmodified in that case. + * + * The following error codes are defined: + * ENOMEM Not enough memory to allocate runlist array. + * EIO Corrupt runlist. + * EINVAL Invalid parameters were passed in. + * ERANGE The two runlists overlap. + * + * FIXME: For now we take the conceptionally simplest approach of creating the + * new runlist disregarding the already existing one and then splicing the + * two into one, if that is possible (we check for overlap and discard the new + * runlist if overlap present before returning NULL, with errno = ERANGE). + */ +static runlist_element *ntfs_mapping_pairs_decompress_i(const ntfs_volume *vol, + const ATTR_RECORD *attr, runlist_element *old_rl) +{ + VCN vcn; /* Current vcn. */ + LCN lcn; /* Current lcn. */ + s64 deltaxcn; /* Change in [vl]cn. */ + runlist_element *rl; /* The output runlist. */ + const u8 *buf; /* Current position in mapping pairs array. */ + const u8 *attr_end; /* End of attribute. */ + int err, rlsize; /* Size of runlist buffer. */ + u16 rlpos; /* Current runlist position in units of + runlist_elements. */ + u8 b; /* Current byte offset in buf. */ + + ntfs_log_trace("Entering for attr 0x%x.\n", + (unsigned)le32_to_cpu(attr->type)); + /* Make sure attr exists and is non-resident. */ + if (!attr || !attr->non_resident || + sle64_to_cpu(attr->lowest_vcn) < (VCN)0) { + errno = EINVAL; + return NULL; + } + /* Start at vcn = lowest_vcn and lcn 0. */ + vcn = sle64_to_cpu(attr->lowest_vcn); + lcn = 0; + /* Get start of the mapping pairs array. */ + buf = (const u8*)attr + le16_to_cpu(attr->mapping_pairs_offset); + attr_end = (const u8*)attr + le32_to_cpu(attr->length); + if (buf < (const u8*)attr || buf > attr_end) { + ntfs_log_debug("Corrupt attribute.\n"); + errno = EIO; + return NULL; + } + /* Current position in runlist array. */ + rlpos = 0; + /* Allocate first 4kiB block and set current runlist size to 4kiB. */ + rlsize = 0x1000; + rl = ntfs_malloc(rlsize); + if (!rl) + return NULL; + /* Insert unmapped starting element if necessary. */ + if (vcn) { + rl->vcn = (VCN)0; + rl->lcn = (LCN)LCN_RL_NOT_MAPPED; + rl->length = vcn; + rlpos++; + } + while (buf < attr_end && *buf) { + /* + * Allocate more memory if needed, including space for the + * not-mapped and terminator elements. + */ + if ((int)((rlpos + 3) * sizeof(*old_rl)) > rlsize) { + runlist_element *rl2; + + rlsize += 0x1000; + rl2 = realloc(rl, rlsize); + if (!rl2) { + int eo = errno; + free(rl); + errno = eo; + return NULL; + } + rl = rl2; + } + /* Enter the current vcn into the current runlist element. */ + rl[rlpos].vcn = vcn; + /* + * Get the change in vcn, i.e. the run length in clusters. + * Doing it this way ensures that we signextend negative values. + * A negative run length doesn't make any sense, but hey, I + * didn't make up the NTFS specs and Windows NT4 treats the run + * length as a signed value so that's how it is... + */ + b = *buf & 0xf; + if (b) { + if (buf + b > attr_end) + goto io_error; + for (deltaxcn = (s8)buf[b--]; b; b--) + deltaxcn = (deltaxcn << 8) + buf[b]; + } else { /* The length entry is compulsory. */ + ntfs_log_debug("Missing length entry in mapping pairs " + "array.\n"); + deltaxcn = (s64)-1; + } + /* + * Assume a negative length to indicate data corruption and + * hence clean-up and return NULL. + */ + if (deltaxcn < 0) { + ntfs_log_debug("Invalid length in mapping pairs array.\n"); + goto err_out; + } + /* + * Enter the current run length into the current runlist + * element. + */ + rl[rlpos].length = deltaxcn; + /* Increment the current vcn by the current run length. */ + vcn += deltaxcn; + /* + * There might be no lcn change at all, as is the case for + * sparse clusters on NTFS 3.0+, in which case we set the lcn + * to LCN_HOLE. + */ + if (!(*buf & 0xf0)) + rl[rlpos].lcn = (LCN)LCN_HOLE; + else { + /* Get the lcn change which really can be negative. */ + u8 b2 = *buf & 0xf; + b = b2 + ((*buf >> 4) & 0xf); + if (buf + b > attr_end) + goto io_error; + for (deltaxcn = (s8)buf[b--]; b > b2; b--) + deltaxcn = (deltaxcn << 8) + buf[b]; + /* Change the current lcn to it's new value. */ + lcn += deltaxcn; +#ifdef DEBUG + /* + * On NTFS 1.2-, apparently can have lcn == -1 to + * indicate a hole. But we haven't verified ourselves + * whether it is really the lcn or the deltaxcn that is + * -1. So if either is found give us a message so we + * can investigate it further! + */ + if (vol->major_ver < 3) { + if (deltaxcn == (LCN)-1) + ntfs_log_debug("lcn delta == -1\n"); + if (lcn == (LCN)-1) + ntfs_log_debug("lcn == -1\n"); + } +#endif + /* Check lcn is not below -1. */ + if (lcn < (LCN)-1) { + ntfs_log_debug("Invalid LCN < -1 in mapping pairs " + "array.\n"); + goto err_out; + } + /* Enter the current lcn into the runlist element. */ + rl[rlpos].lcn = lcn; + } + /* Get to the next runlist element. */ + rlpos++; + /* Increment the buffer position to the next mapping pair. */ + buf += (*buf & 0xf) + ((*buf >> 4) & 0xf) + 1; + } + if (buf >= attr_end) + goto io_error; + /* + * If there is a highest_vcn specified, it must be equal to the final + * vcn in the runlist - 1, or something has gone badly wrong. + */ + deltaxcn = sle64_to_cpu(attr->highest_vcn); + if (deltaxcn && vcn - 1 != deltaxcn) { +mpa_err: + ntfs_log_debug("Corrupt mapping pairs array in non-resident " + "attribute.\n"); + goto err_out; + } + /* Setup not mapped runlist element if this is the base extent. */ + if (!attr->lowest_vcn) { + VCN max_cluster; + + max_cluster = ((sle64_to_cpu(attr->allocated_size) + + vol->cluster_size - 1) >> + vol->cluster_size_bits) - 1; + /* + * A highest_vcn of zero means this is a single extent + * attribute so simply terminate the runlist with LCN_ENOENT). + */ + if (deltaxcn) { + /* + * If there is a difference between the highest_vcn and + * the highest cluster, the runlist is either corrupt + * or, more likely, there are more extents following + * this one. + */ + if (deltaxcn < max_cluster) { + ntfs_log_debug("More extents to follow; deltaxcn = " + "0x%llx, max_cluster = 0x%llx\n", + (long long)deltaxcn, + (long long)max_cluster); + rl[rlpos].vcn = vcn; + vcn += rl[rlpos].length = max_cluster - deltaxcn; + rl[rlpos].lcn = (LCN)LCN_RL_NOT_MAPPED; + rlpos++; + } else if (deltaxcn > max_cluster) { + ntfs_log_debug("Corrupt attribute. deltaxcn = " + "0x%llx, max_cluster = 0x%llx\n", + (long long)deltaxcn, + (long long)max_cluster); + goto mpa_err; + } + } + rl[rlpos].lcn = (LCN)LCN_ENOENT; + } else /* Not the base extent. There may be more extents to follow. */ + rl[rlpos].lcn = (LCN)LCN_RL_NOT_MAPPED; + + /* Setup terminating runlist element. */ + rl[rlpos].vcn = vcn; + rl[rlpos].length = (s64)0; + /* If no existing runlist was specified, we are done. */ + if (!old_rl) { + ntfs_log_debug("Mapping pairs array successfully decompressed:\n"); + ntfs_debug_runlist_dump(rl); + return rl; + } + /* Now combine the new and old runlists checking for overlaps. */ + old_rl = ntfs_runlists_merge(old_rl, rl); + if (old_rl) + return old_rl; + err = errno; + free(rl); + ntfs_log_debug("Failed to merge runlists.\n"); + errno = err; + return NULL; +io_error: + ntfs_log_debug("Corrupt attribute.\n"); +err_out: + free(rl); + errno = EIO; + return NULL; +} + +runlist_element *ntfs_mapping_pairs_decompress(const ntfs_volume *vol, + const ATTR_RECORD *attr, runlist_element *old_rl) +{ + runlist_element *rle; + + ntfs_log_enter("Entering\n"); + rle = ntfs_mapping_pairs_decompress_i(vol, attr, old_rl); + ntfs_log_leave("\n"); + return rle; +} + +/** + * ntfs_rl_vcn_to_lcn - convert a vcn into a lcn given a runlist + * @rl: runlist to use for conversion + * @vcn: vcn to convert + * + * Convert the virtual cluster number @vcn of an attribute into a logical + * cluster number (lcn) of a device using the runlist @rl to map vcns to their + * corresponding lcns. + * + * Since lcns must be >= 0, we use negative return values with special meaning: + * + * Return value Meaning / Description + * ================================================== + * -1 = LCN_HOLE Hole / not allocated on disk. + * -2 = LCN_RL_NOT_MAPPED This is part of the runlist which has not been + * inserted into the runlist yet. + * -3 = LCN_ENOENT There is no such vcn in the attribute. + * -4 = LCN_EINVAL Input parameter error. + */ +LCN ntfs_rl_vcn_to_lcn(const runlist_element *rl, const VCN vcn) +{ + int i; + + if (vcn < (VCN)0) + return (LCN)LCN_EINVAL; + /* + * If rl is NULL, assume that we have found an unmapped runlist. The + * caller can then attempt to map it and fail appropriately if + * necessary. + */ + if (!rl) + return (LCN)LCN_RL_NOT_MAPPED; + + /* Catch out of lower bounds vcn. */ + if (vcn < rl[0].vcn) + return (LCN)LCN_ENOENT; + + for (i = 0; rl[i].length; i++) { + if (vcn < rl[i+1].vcn) { + if (rl[i].lcn >= (LCN)0) + return rl[i].lcn + (vcn - rl[i].vcn); + return rl[i].lcn; + } + } + /* + * The terminator element is setup to the correct value, i.e. one of + * LCN_HOLE, LCN_RL_NOT_MAPPED, or LCN_ENOENT. + */ + if (rl[i].lcn < (LCN)0) + return rl[i].lcn; + /* Just in case... We could replace this with BUG() some day. */ + return (LCN)LCN_ENOENT; +} + +/** + * ntfs_rl_pread - gather read from disk + * @vol: ntfs volume to read from + * @rl: runlist specifying where to read the data from + * @pos: byte position within runlist @rl at which to begin the read + * @count: number of bytes to read + * @b: data buffer into which to read from disk + * + * This function will read @count bytes from the volume @vol to the data buffer + * @b gathering the data as specified by the runlist @rl. The read begins at + * offset @pos into the runlist @rl. + * + * On success, return the number of successfully read bytes. If this number is + * lower than @count this means that the read reached end of file or that an + * error was encountered during the read so that the read is partial. 0 means + * nothing was read (also return 0 when @count is 0). + * + * On error and nothing has been read, return -1 with errno set appropriately + * to the return code of ntfs_pread(), or to EINVAL in case of invalid + * arguments. + * + * NOTE: If we encounter EOF while reading we return EIO because we assume that + * the run list must point to valid locations within the ntfs volume. + */ +s64 ntfs_rl_pread(const ntfs_volume *vol, const runlist_element *rl, + const s64 pos, s64 count, void *b) +{ + s64 bytes_read, to_read, ofs, total; + int err = EIO; + + if (!vol || !rl || pos < 0 || count < 0) { + errno = EINVAL; + ntfs_log_perror("Failed to read runlist [vol: %p rl: %p " + "pos: %lld count: %lld]", vol, rl, + (long long)pos, (long long)count); + return -1; + } + if (!count) + return count; + /* Seek in @rl to the run containing @pos. */ + for (ofs = 0; rl->length && (ofs + (rl->length << + vol->cluster_size_bits) <= pos); rl++) + ofs += (rl->length << vol->cluster_size_bits); + /* Offset in the run at which to begin reading. */ + ofs = pos - ofs; + for (total = 0LL; count; rl++, ofs = 0) { + if (!rl->length) + goto rl_err_out; + if (rl->lcn < (LCN)0) { + if (rl->lcn != (LCN)LCN_HOLE) + goto rl_err_out; + /* It is a hole. Just fill buffer @b with zeroes. */ + to_read = min(count, (rl->length << + vol->cluster_size_bits) - ofs); + memset(b, 0, to_read); + /* Update counters and proceed with next run. */ + total += to_read; + count -= to_read; + b = (u8*)b + to_read; + continue; + } + /* It is a real lcn, read it from the volume. */ + to_read = min(count, (rl->length << vol->cluster_size_bits) - + ofs); +retry: + bytes_read = ntfs_pread(vol->dev, (rl->lcn << + vol->cluster_size_bits) + ofs, to_read, b); + /* If everything ok, update progress counters and continue. */ + if (bytes_read > 0) { + total += bytes_read; + count -= bytes_read; + b = (u8*)b + bytes_read; + continue; + } + /* If the syscall was interrupted, try again. */ + if (bytes_read == (s64)-1 && errno == EINTR) + goto retry; + if (bytes_read == (s64)-1) + err = errno; + goto rl_err_out; + } + /* Finally, return the number of bytes read. */ + return total; +rl_err_out: + if (total) + return total; + errno = err; + return -1; +} + +/** + * ntfs_rl_pwrite - scatter write to disk + * @vol: ntfs volume to write to + * @rl: runlist entry specifying where to write the data to + * @ofs: offset in file for runlist element indicated in @rl + * @pos: byte position from runlist beginning at which to begin the write + * @count: number of bytes to write + * @b: data buffer to write to disk + * + * This function will write @count bytes from data buffer @b to the volume @vol + * scattering the data as specified by the runlist @rl. The write begins at + * offset @pos into the runlist @rl. If a run is sparse then the related buffer + * data is ignored which means that the caller must ensure they are consistent. + * + * On success, return the number of successfully written bytes. If this number + * is lower than @count this means that the write has been interrupted in + * flight or that an error was encountered during the write so that the write + * is partial. 0 means nothing was written (also return 0 when @count is 0). + * + * On error and nothing has been written, return -1 with errno set + * appropriately to the return code of ntfs_pwrite(), or to to EINVAL in case + * of invalid arguments. + */ +s64 ntfs_rl_pwrite(const ntfs_volume *vol, const runlist_element *rl, + s64 ofs, const s64 pos, s64 count, void *b) +{ + s64 written, to_write, total = 0; + int err = EIO; + + if (!vol || !rl || pos < 0 || count < 0) { + errno = EINVAL; + ntfs_log_perror("Failed to write runlist [vol: %p rl: %p " + "pos: %lld count: %lld]", vol, rl, + (long long)pos, (long long)count); + goto errno_set; + } + if (!count) + goto out; + /* Seek in @rl to the run containing @pos. */ + while (rl->length && (ofs + (rl->length << + vol->cluster_size_bits) <= pos)) { + ofs += (rl->length << vol->cluster_size_bits); + rl++; + } + /* Offset in the run at which to begin writing. */ + ofs = pos - ofs; + for (total = 0LL; count; rl++, ofs = 0) { + if (!rl->length) + goto rl_err_out; + if (rl->lcn < (LCN)0) { + + if (rl->lcn != (LCN)LCN_HOLE) + goto rl_err_out; + + to_write = min(count, (rl->length << + vol->cluster_size_bits) - ofs); + + total += to_write; + count -= to_write; + b = (u8*)b + to_write; + continue; + } + /* It is a real lcn, write it to the volume. */ + to_write = min(count, (rl->length << vol->cluster_size_bits) - + ofs); +retry: + if (!NVolReadOnly(vol)) + written = ntfs_pwrite(vol->dev, (rl->lcn << + vol->cluster_size_bits) + ofs, + to_write, b); + else + written = to_write; + /* If everything ok, update progress counters and continue. */ + if (written > 0) { + total += written; + count -= written; + b = (u8*)b + written; + continue; + } + /* If the syscall was interrupted, try again. */ + if (written == (s64)-1 && errno == EINTR) + goto retry; + if (written == (s64)-1) + err = errno; + goto rl_err_out; + } +out: + return total; +rl_err_out: + if (total) + goto out; + errno = err; +errno_set: + total = -1; + goto out; +} + +/** + * ntfs_get_nr_significant_bytes - get number of bytes needed to store a number + * @n: number for which to get the number of bytes for + * + * Return the number of bytes required to store @n unambiguously as + * a signed number. + * + * This is used in the context of the mapping pairs array to determine how + * many bytes will be needed in the array to store a given logical cluster + * number (lcn) or a specific run length. + * + * Return the number of bytes written. This function cannot fail. + */ +int ntfs_get_nr_significant_bytes(const s64 n) +{ + u64 l; + int i; + + l = (n < 0 ? ~n : n); + i = 1; + if (l >= 128) { + l >>= 7; + do { + i++; + l >>= 8; + } while (l); + } + return i; +} + +/** + * ntfs_get_size_for_mapping_pairs - get bytes needed for mapping pairs array + * @vol: ntfs volume (needed for the ntfs version) + * @rl: runlist for which to determine the size of the mapping pairs + * @start_vcn: vcn at which to start the mapping pairs array + * + * Walk the runlist @rl and calculate the size in bytes of the mapping pairs + * array corresponding to the runlist @rl, starting at vcn @start_vcn. This + * for example allows us to allocate a buffer of the right size when building + * the mapping pairs array. + * + * If @rl is NULL, just return 1 (for the single terminator byte). + * + * Return the calculated size in bytes on success. On error, return -1 with + * errno set to the error code. The following error codes are defined: + * EINVAL - Run list contains unmapped elements. Make sure to only pass + * fully mapped runlists to this function. + * - @start_vcn is invalid. + * EIO - The runlist is corrupt. + */ +int ntfs_get_size_for_mapping_pairs(const ntfs_volume *vol, + const runlist_element *rl, const VCN start_vcn, int max_size) +{ + LCN prev_lcn; + int rls; + + if (start_vcn < 0) { + ntfs_log_trace("start_vcn %lld (should be >= 0)\n", + (long long) start_vcn); + errno = EINVAL; + goto errno_set; + } + if (!rl) { + if (start_vcn) { + ntfs_log_trace("rl NULL, start_vcn %lld (should be > 0)\n", + (long long) start_vcn); + errno = EINVAL; + goto errno_set; + } + rls = 1; + goto out; + } + /* Skip to runlist element containing @start_vcn. */ + while (rl->length && start_vcn >= rl[1].vcn) + rl++; + if ((!rl->length && start_vcn > rl->vcn) || start_vcn < rl->vcn) { + errno = EINVAL; + goto errno_set; + } + prev_lcn = 0; + /* Always need the terminating zero byte. */ + rls = 1; + /* Do the first partial run if present. */ + if (start_vcn > rl->vcn) { + s64 delta; + + /* We know rl->length != 0 already. */ + if (rl->length < 0 || rl->lcn < LCN_HOLE) + goto err_out; + delta = start_vcn - rl->vcn; + /* Header byte + length. */ + rls += 1 + ntfs_get_nr_significant_bytes(rl->length - delta); + /* + * If the logical cluster number (lcn) denotes a hole and we + * are on NTFS 3.0+, we don't store it at all, i.e. we need + * zero space. On earlier NTFS versions we just store the lcn. + * Note: this assumes that on NTFS 1.2-, holes are stored with + * an lcn of -1 and not a delta_lcn of -1 (unless both are -1). + */ + if (rl->lcn >= 0 || vol->major_ver < 3) { + prev_lcn = rl->lcn; + if (rl->lcn >= 0) + prev_lcn += delta; + /* Change in lcn. */ + rls += ntfs_get_nr_significant_bytes(prev_lcn); + } + /* Go to next runlist element. */ + rl++; + } + /* Do the full runs. */ + for (; rl->length && (rls <= max_size); rl++) { + if (rl->length < 0 || rl->lcn < LCN_HOLE) + goto err_out; + /* Header byte + length. */ + rls += 1 + ntfs_get_nr_significant_bytes(rl->length); + /* + * If the logical cluster number (lcn) denotes a hole and we + * are on NTFS 3.0+, we don't store it at all, i.e. we need + * zero space. On earlier NTFS versions we just store the lcn. + * Note: this assumes that on NTFS 1.2-, holes are stored with + * an lcn of -1 and not a delta_lcn of -1 (unless both are -1). + */ + if (rl->lcn >= 0 || vol->major_ver < 3) { + /* Change in lcn. */ + rls += ntfs_get_nr_significant_bytes(rl->lcn - + prev_lcn); + prev_lcn = rl->lcn; + } + } +out: + return rls; +err_out: + if (rl->lcn == LCN_RL_NOT_MAPPED) + errno = EINVAL; + else + errno = EIO; +errno_set: + rls = -1; + goto out; +} + +/** + * ntfs_write_significant_bytes - write the significant bytes of a number + * @dst: destination buffer to write to + * @dst_max: pointer to last byte of destination buffer for bounds checking + * @n: number whose significant bytes to write + * + * Store in @dst, the minimum bytes of the number @n which are required to + * identify @n unambiguously as a signed number, taking care not to exceed + * @dest_max, the maximum position within @dst to which we are allowed to + * write. + * + * This is used when building the mapping pairs array of a runlist to compress + * a given logical cluster number (lcn) or a specific run length to the minimum + * size possible. + * + * Return the number of bytes written on success. On error, i.e. the + * destination buffer @dst is too small, return -1 with errno set ENOSPC. + */ +int ntfs_write_significant_bytes(u8 *dst, const u8 *dst_max, const s64 n) +{ + s64 l = n; + int i; + s8 j; + + i = 0; + do { + if (dst > dst_max) + goto err_out; + *dst++ = l & 0xffLL; + l >>= 8; + i++; + } while (l != 0LL && l != -1LL); + j = (n >> 8 * (i - 1)) & 0xff; + /* If the sign bit is wrong, we need an extra byte. */ + if (n < 0LL && j >= 0) { + if (dst > dst_max) + goto err_out; + i++; + *dst = (u8)-1; + } else if (n > 0LL && j < 0) { + if (dst > dst_max) + goto err_out; + i++; + *dst = 0; + } + return i; +err_out: + errno = ENOSPC; + return -1; +} + +/** + * ntfs_mapping_pairs_build - build the mapping pairs array from a runlist + * @vol: ntfs volume (needed for the ntfs version) + * @dst: destination buffer to which to write the mapping pairs array + * @dst_len: size of destination buffer @dst in bytes + * @rl: runlist for which to build the mapping pairs array + * @start_vcn: vcn at which to start the mapping pairs array + * @stop_vcn: first vcn outside destination buffer on success or ENOSPC error + * + * Create the mapping pairs array from the runlist @rl, starting at vcn + * @start_vcn and save the array in @dst. @dst_len is the size of @dst in + * bytes and it should be at least equal to the value obtained by calling + * ntfs_get_size_for_mapping_pairs(). + * + * If @rl is NULL, just write a single terminator byte to @dst. + * + * On success or ENOSPC error, if @stop_vcn is not NULL, *@stop_vcn is set to + * the first vcn outside the destination buffer. Note that on error @dst has + * been filled with all the mapping pairs that will fit, thus it can be treated + * as partial success, in that a new attribute extent needs to be created or the + * next extent has to be used and the mapping pairs build has to be continued + * with @start_vcn set to *@stop_vcn. + * + * Return 0 on success. On error, return -1 with errno set to the error code. + * The following error codes are defined: + * EINVAL - Run list contains unmapped elements. Make sure to only pass + * fully mapped runlists to this function. + * - @start_vcn is invalid. + * EIO - The runlist is corrupt. + * ENOSPC - The destination buffer is too small. + */ +int ntfs_mapping_pairs_build(const ntfs_volume *vol, u8 *dst, + const int dst_len, const runlist_element *rl, + const VCN start_vcn, runlist_element const **stop_rl) +{ + LCN prev_lcn; + u8 *dst_max, *dst_next; + s8 len_len, lcn_len; + int ret = 0; + + if (start_vcn < 0) + goto val_err; + if (!rl) { + if (start_vcn) + goto val_err; + if (stop_rl) + *stop_rl = rl; + if (dst_len < 1) + goto nospc_err; + goto ok; + } + /* Skip to runlist element containing @start_vcn. */ + while (rl->length && start_vcn >= rl[1].vcn) + rl++; + if ((!rl->length && start_vcn > rl->vcn) || start_vcn < rl->vcn) + goto val_err; + /* + * @dst_max is used for bounds checking in + * ntfs_write_significant_bytes(). + */ + dst_max = dst + dst_len - 1; + prev_lcn = 0; + /* Do the first partial run if present. */ + if (start_vcn > rl->vcn) { + s64 delta; + + /* We know rl->length != 0 already. */ + if (rl->length < 0 || rl->lcn < LCN_HOLE) + goto err_out; + delta = start_vcn - rl->vcn; + /* Write length. */ + len_len = ntfs_write_significant_bytes(dst + 1, dst_max, + rl->length - delta); + if (len_len < 0) + goto size_err; + /* + * If the logical cluster number (lcn) denotes a hole and we + * are on NTFS 3.0+, we don't store it at all, i.e. we need + * zero space. On earlier NTFS versions we just write the lcn + * change. FIXME: Do we need to write the lcn change or just + * the lcn in that case? Not sure as I have never seen this + * case on NT4. - We assume that we just need to write the lcn + * change until someone tells us otherwise... (AIA) + */ + if (rl->lcn >= 0 || vol->major_ver < 3) { + prev_lcn = rl->lcn; + if (rl->lcn >= 0) + prev_lcn += delta; + /* Write change in lcn. */ + lcn_len = ntfs_write_significant_bytes(dst + 1 + + len_len, dst_max, prev_lcn); + if (lcn_len < 0) + goto size_err; + } else + lcn_len = 0; + dst_next = dst + len_len + lcn_len + 1; + if (dst_next > dst_max) + goto size_err; + /* Update header byte. */ + *dst = lcn_len << 4 | len_len; + /* Position at next mapping pairs array element. */ + dst = dst_next; + /* Go to next runlist element. */ + rl++; + } + /* Do the full runs. */ + for (; rl->length; rl++) { + if (rl->length < 0 || rl->lcn < LCN_HOLE) + goto err_out; + /* Write length. */ + len_len = ntfs_write_significant_bytes(dst + 1, dst_max, + rl->length); + if (len_len < 0) + goto size_err; + /* + * If the logical cluster number (lcn) denotes a hole and we + * are on NTFS 3.0+, we don't store it at all, i.e. we need + * zero space. On earlier NTFS versions we just write the lcn + * change. FIXME: Do we need to write the lcn change or just + * the lcn in that case? Not sure as I have never seen this + * case on NT4. - We assume that we just need to write the lcn + * change until someone tells us otherwise... (AIA) + */ + if (rl->lcn >= 0 || vol->major_ver < 3) { + /* Write change in lcn. */ + lcn_len = ntfs_write_significant_bytes(dst + 1 + + len_len, dst_max, rl->lcn - prev_lcn); + if (lcn_len < 0) + goto size_err; + prev_lcn = rl->lcn; + } else + lcn_len = 0; + dst_next = dst + len_len + lcn_len + 1; + if (dst_next > dst_max) + goto size_err; + /* Update header byte. */ + *dst = lcn_len << 4 | len_len; + /* Position at next mapping pairs array element. */ + dst += 1 + len_len + lcn_len; + } + /* Set stop vcn. */ + if (stop_rl) + *stop_rl = rl; +ok: + /* Add terminator byte. */ + *dst = 0; +out: + return ret; +size_err: + /* Set stop vcn. */ + if (stop_rl) + *stop_rl = rl; + /* Add terminator byte. */ + *dst = 0; +nospc_err: + errno = ENOSPC; + goto errno_set; +val_err: + errno = EINVAL; + goto errno_set; +err_out: + if (rl->lcn == LCN_RL_NOT_MAPPED) + errno = EINVAL; + else + errno = EIO; +errno_set: + ret = -1; + goto out; +} + +/** + * ntfs_rl_truncate - truncate a runlist starting at a specified vcn + * @arl: address of runlist to truncate + * @start_vcn: first vcn which should be cut off + * + * Truncate the runlist *@arl starting at vcn @start_vcn as well as the memory + * buffer holding the runlist. + * + * Return 0 on success and -1 on error with errno set to the error code. + * + * NOTE: @arl is the address of the runlist. We need the address so we can + * modify the pointer to the runlist with the new, reallocated memory buffer. + */ +int ntfs_rl_truncate(runlist **arl, const VCN start_vcn) +{ + runlist *rl; + BOOL is_end = FALSE; + + if (!arl || !*arl) { + errno = EINVAL; + if (!arl) + ntfs_log_perror("rl_truncate error: arl: %p", arl); + else + ntfs_log_perror("rl_truncate error:" + " arl: %p *arl: %p", arl, *arl); + return -1; + } + + rl = *arl; + + if (start_vcn < rl->vcn) { + errno = EINVAL; + ntfs_log_perror("Start_vcn lies outside front of runlist"); + return -1; + } + + /* Find the starting vcn in the run list. */ + while (rl->length) { + if (start_vcn < rl[1].vcn) + break; + rl++; + } + + if (!rl->length) { + errno = EIO; + ntfs_log_trace("Truncating already truncated runlist?\n"); + return -1; + } + + /* Truncate the run. */ + rl->length = start_vcn - rl->vcn; + + /* + * If a run was partially truncated, make the following runlist + * element a terminator instead of the truncated runlist + * element itself. + */ + if (rl->length) { + ++rl; + if (!rl->length) + is_end = TRUE; + rl->vcn = start_vcn; + rl->length = 0; + } + rl->lcn = (LCN)LCN_ENOENT; + /** + * Reallocate memory if necessary. + * FIXME: Below code is broken, because runlist allocations must be + * a multiply of 4096. The code caused crashes and corruptions. + */ +/* + if (!is_end) { + size_t new_size = (rl - *arl + 1) * sizeof(runlist_element); + rl = realloc(*arl, new_size); + if (rl) + *arl = rl; + } +*/ + return 0; +} + +/** + * ntfs_rl_sparse - check whether runlist have sparse regions or not. + * @rl: runlist to check + * + * Return 1 if have, 0 if not, -1 on error with errno set to the error code. + */ +int ntfs_rl_sparse(runlist *rl) +{ + runlist *rlc; + + if (!rl) { + errno = EINVAL; + ntfs_log_perror("%s: ", __FUNCTION__); + return -1; + } + + for (rlc = rl; rlc->length; rlc++) + if (rlc->lcn < 0) { + if (rlc->lcn != LCN_HOLE) { + errno = EINVAL; + ntfs_log_perror("%s: bad runlist", __FUNCTION__); + return -1; + } + return 1; + } + return 0; +} + +/** + * ntfs_rl_get_compressed_size - calculate length of non sparse regions + * @vol: ntfs volume (need for cluster size) + * @rl: runlist to calculate for + * + * Return compressed size or -1 on error with errno set to the error code. + */ +s64 ntfs_rl_get_compressed_size(ntfs_volume *vol, runlist *rl) +{ + runlist *rlc; + s64 ret = 0; + + if (!rl) { + errno = EINVAL; + ntfs_log_perror("%s: ", __FUNCTION__); + return -1; + } + + for (rlc = rl; rlc->length; rlc++) { + if (rlc->lcn < 0) { + if (rlc->lcn != LCN_HOLE) { + errno = EINVAL; + ntfs_log_perror("%s: bad runlist", __FUNCTION__); + return -1; + } + } else + ret += rlc->length; + } + return ret << vol->cluster_size_bits; +} + + +#ifdef NTFS_TEST +/** + * test_rl_helper + */ +#define MKRL(R,V,L,S) \ + (R)->vcn = V; \ + (R)->lcn = L; \ + (R)->length = S; +/* +} +*/ +/** + * test_rl_dump_runlist - Runlist test: Display the contents of a runlist + * @rl: + * + * Description... + * + * Returns: + */ +static void test_rl_dump_runlist(const runlist_element *rl) +{ + int abbr = 0; /* abbreviate long lists */ + int len = 0; + int i; + const char *lcn_str[5] = { "HOLE", "NOTMAP", "ENOENT", "XXXX" }; + + if (!rl) { + printf(" Run list not present.\n"); + return; + } + + if (abbr) + for (len = 0; rl[len].length; len++) ; + + printf(" VCN LCN len\n"); + for (i = 0; ; i++, rl++) { + LCN lcn = rl->lcn; + + if ((abbr) && (len > 20)) { + if (i == 4) + printf(" ...\n"); + if ((i > 3) && (i < (len - 3))) + continue; + } + + if (lcn < (LCN)0) { + int ind = -lcn - 1; + + if (ind > -LCN_ENOENT - 1) + ind = 3; + printf("%8lld %8s %8lld\n", + rl->vcn, lcn_str[ind], rl->length); + } else + printf("%8lld %8lld %8lld\n", + rl->vcn, rl->lcn, rl->length); + if (!rl->length) + break; + } + if ((abbr) && (len > 20)) + printf(" (%d entries)\n", len+1); + printf("\n"); +} + +/** + * test_rl_runlists_merge - Runlist test: Merge two runlists + * @drl: + * @srl: + * + * Description... + * + * Returns: + */ +static runlist_element * test_rl_runlists_merge(runlist_element *drl, runlist_element *srl) +{ + runlist_element *res = NULL; + + printf("dst:\n"); + test_rl_dump_runlist(drl); + printf("src:\n"); + test_rl_dump_runlist(srl); + + res = ntfs_runlists_merge(drl, srl); + + printf("res:\n"); + test_rl_dump_runlist(res); + + return res; +} + +/** + * test_rl_read_buffer - Runlist test: Read a file containing a runlist + * @file: + * @buf: + * @bufsize: + * + * Description... + * + * Returns: + */ +static int test_rl_read_buffer(const char *file, u8 *buf, int bufsize) +{ + FILE *fptr; + + fptr = fopen(file, "r"); + if (!fptr) { + printf("open %s\n", file); + return 0; + } + + if (fread(buf, bufsize, 1, fptr) == 99) { + printf("read %s\n", file); + return 0; + } + + fclose(fptr); + return 1; +} + +/** + * test_rl_pure_src - Runlist test: Complicate the simple tests a little + * @contig: + * @multi: + * @vcn: + * @len: + * + * Description... + * + * Returns: + */ +static runlist_element * test_rl_pure_src(BOOL contig, BOOL multi, int vcn, int len) +{ + runlist_element *result; + int fudge; + + if (contig) + fudge = 0; + else + fudge = 999; + + result = ntfs_malloc(4096); + if (!result) + return NULL; + + if (multi) { + MKRL(result+0, vcn + (0*len/4), fudge + vcn + 1000 + (0*len/4), len / 4) + MKRL(result+1, vcn + (1*len/4), fudge + vcn + 1000 + (1*len/4), len / 4) + MKRL(result+2, vcn + (2*len/4), fudge + vcn + 1000 + (2*len/4), len / 4) + MKRL(result+3, vcn + (3*len/4), fudge + vcn + 1000 + (3*len/4), len / 4) + MKRL(result+4, vcn + (4*len/4), LCN_RL_NOT_MAPPED, 0) + } else { + MKRL(result+0, vcn, fudge + vcn + 1000, len) + MKRL(result+1, vcn + len, LCN_RL_NOT_MAPPED, 0) + } + return result; +} + +/** + * test_rl_pure_test - Runlist test: Perform tests using simple runlists + * @test: + * @contig: + * @multi: + * @vcn: + * @len: + * @file: + * @size: + * + * Description... + * + * Returns: + */ +static void test_rl_pure_test(int test, BOOL contig, BOOL multi, int vcn, int len, runlist_element *file, int size) +{ + runlist_element *src; + runlist_element *dst; + runlist_element *res; + + src = test_rl_pure_src(contig, multi, vcn, len); + dst = ntfs_malloc(4096); + if (!src || !dst) { + printf("Test %2d ---------- FAILED! (no free memory?)\n", test); + return; + } + + memcpy(dst, file, size); + + printf("Test %2d ----------\n", test); + res = test_rl_runlists_merge(dst, src); + + free(res); +} + +/** + * test_rl_pure - Runlist test: Create tests using simple runlists + * @contig: + * @multi: + * + * Description... + * + * Returns: + */ +static void test_rl_pure(char *contig, char *multi) +{ + /* VCN, LCN, len */ + static runlist_element file1[] = { + { 0, -1, 100 }, /* HOLE */ + { 100, 1100, 100 }, /* DATA */ + { 200, -1, 100 }, /* HOLE */ + { 300, 1300, 100 }, /* DATA */ + { 400, -1, 100 }, /* HOLE */ + { 500, -3, 0 } /* NOENT */ + }; + static runlist_element file2[] = { + { 0, 1000, 100 }, /* DATA */ + { 100, -1, 100 }, /* HOLE */ + { 200, -3, 0 } /* NOENT */ + }; + static runlist_element file3[] = { + { 0, 1000, 100 }, /* DATA */ + { 100, -3, 0 } /* NOENT */ + }; + static runlist_element file4[] = { + { 0, -3, 0 } /* NOENT */ + }; + static runlist_element file5[] = { + { 0, -2, 100 }, /* NOTMAP */ + { 100, 1100, 100 }, /* DATA */ + { 200, -2, 100 }, /* NOTMAP */ + { 300, 1300, 100 }, /* DATA */ + { 400, -2, 100 }, /* NOTMAP */ + { 500, -3, 0 } /* NOENT */ + }; + static runlist_element file6[] = { + { 0, 1000, 100 }, /* DATA */ + { 100, -2, 100 }, /* NOTMAP */ + { 200, -3, 0 } /* NOENT */ + }; + BOOL c, m; + + if (strcmp(contig, "contig") == 0) + c = TRUE; + else if (strcmp(contig, "noncontig") == 0) + c = FALSE; + else { + printf("rl pure [contig|noncontig] [single|multi]\n"); + return; + } + if (strcmp(multi, "multi") == 0) + m = TRUE; + else if (strcmp(multi, "single") == 0) + m = FALSE; + else { + printf("rl pure [contig|noncontig] [single|multi]\n"); + return; + } + + test_rl_pure_test(1, c, m, 0, 40, file1, sizeof(file1)); + test_rl_pure_test(2, c, m, 40, 40, file1, sizeof(file1)); + test_rl_pure_test(3, c, m, 60, 40, file1, sizeof(file1)); + test_rl_pure_test(4, c, m, 0, 100, file1, sizeof(file1)); + test_rl_pure_test(5, c, m, 200, 40, file1, sizeof(file1)); + test_rl_pure_test(6, c, m, 240, 40, file1, sizeof(file1)); + test_rl_pure_test(7, c, m, 260, 40, file1, sizeof(file1)); + test_rl_pure_test(8, c, m, 200, 100, file1, sizeof(file1)); + test_rl_pure_test(9, c, m, 400, 40, file1, sizeof(file1)); + test_rl_pure_test(10, c, m, 440, 40, file1, sizeof(file1)); + test_rl_pure_test(11, c, m, 460, 40, file1, sizeof(file1)); + test_rl_pure_test(12, c, m, 400, 100, file1, sizeof(file1)); + test_rl_pure_test(13, c, m, 160, 100, file2, sizeof(file2)); + test_rl_pure_test(14, c, m, 100, 140, file2, sizeof(file2)); + test_rl_pure_test(15, c, m, 200, 40, file2, sizeof(file2)); + test_rl_pure_test(16, c, m, 240, 40, file2, sizeof(file2)); + test_rl_pure_test(17, c, m, 100, 40, file3, sizeof(file3)); + test_rl_pure_test(18, c, m, 140, 40, file3, sizeof(file3)); + test_rl_pure_test(19, c, m, 0, 40, file4, sizeof(file4)); + test_rl_pure_test(20, c, m, 40, 40, file4, sizeof(file4)); + test_rl_pure_test(21, c, m, 0, 40, file5, sizeof(file5)); + test_rl_pure_test(22, c, m, 40, 40, file5, sizeof(file5)); + test_rl_pure_test(23, c, m, 60, 40, file5, sizeof(file5)); + test_rl_pure_test(24, c, m, 0, 100, file5, sizeof(file5)); + test_rl_pure_test(25, c, m, 200, 40, file5, sizeof(file5)); + test_rl_pure_test(26, c, m, 240, 40, file5, sizeof(file5)); + test_rl_pure_test(27, c, m, 260, 40, file5, sizeof(file5)); + test_rl_pure_test(28, c, m, 200, 100, file5, sizeof(file5)); + test_rl_pure_test(29, c, m, 400, 40, file5, sizeof(file5)); + test_rl_pure_test(30, c, m, 440, 40, file5, sizeof(file5)); + test_rl_pure_test(31, c, m, 460, 40, file5, sizeof(file5)); + test_rl_pure_test(32, c, m, 400, 100, file5, sizeof(file5)); + test_rl_pure_test(33, c, m, 160, 100, file6, sizeof(file6)); + test_rl_pure_test(34, c, m, 100, 140, file6, sizeof(file6)); +} + +/** + * test_rl_zero - Runlist test: Merge a zero-length runlist + * + * Description... + * + * Returns: + */ +static void test_rl_zero(void) +{ + runlist_element *jim = NULL; + runlist_element *bob = NULL; + + bob = calloc(3, sizeof(runlist_element)); + if (!bob) + return; + + MKRL(bob+0, 10, 99, 5) + MKRL(bob+1, 15, LCN_RL_NOT_MAPPED, 0) + + jim = test_rl_runlists_merge(jim, bob); + if (!jim) + return; + + free(jim); +} + +/** + * test_rl_frag_combine - Runlist test: Perform tests using fragmented files + * @vol: + * @attr1: + * @attr2: + * @attr3: + * + * Description... + * + * Returns: + */ +static void test_rl_frag_combine(ntfs_volume *vol, ATTR_RECORD *attr1, ATTR_RECORD *attr2, ATTR_RECORD *attr3) +{ + runlist_element *run1; + runlist_element *run2; + runlist_element *run3; + + run1 = ntfs_mapping_pairs_decompress(vol, attr1, NULL); + if (!run1) + return; + + run2 = ntfs_mapping_pairs_decompress(vol, attr2, NULL); + if (!run2) + return; + + run1 = test_rl_runlists_merge(run1, run2); + + run3 = ntfs_mapping_pairs_decompress(vol, attr3, NULL); + if (!run3) + return; + + run1 = test_rl_runlists_merge(run1, run3); + + free(run1); +} + +/** + * test_rl_frag - Runlist test: Create tests using very fragmented files + * @test: + * + * Description... + * + * Returns: + */ +static void test_rl_frag(char *test) +{ + ntfs_volume vol; + ATTR_RECORD *attr1 = ntfs_malloc(1024); + ATTR_RECORD *attr2 = ntfs_malloc(1024); + ATTR_RECORD *attr3 = ntfs_malloc(1024); + + if (!attr1 || !attr2 || !attr3) + goto out; + + vol.sb = NULL; + vol.sector_size_bits = 9; + vol.cluster_size = 2048; + vol.cluster_size_bits = 11; + vol.major_ver = 3; + + if (!test_rl_read_buffer("runlist-data/attr1.bin", (u8*) attr1, 1024)) + goto out; + if (!test_rl_read_buffer("runlist-data/attr2.bin", (u8*) attr2, 1024)) + goto out; + if (!test_rl_read_buffer("runlist-data/attr3.bin", (u8*) attr3, 1024)) + goto out; + + if (strcmp(test, "123") == 0) test_rl_frag_combine(&vol, attr1, attr2, attr3); + else if (strcmp(test, "132") == 0) test_rl_frag_combine(&vol, attr1, attr3, attr2); + else if (strcmp(test, "213") == 0) test_rl_frag_combine(&vol, attr2, attr1, attr3); + else if (strcmp(test, "231") == 0) test_rl_frag_combine(&vol, attr2, attr3, attr1); + else if (strcmp(test, "312") == 0) test_rl_frag_combine(&vol, attr3, attr1, attr2); + else if (strcmp(test, "321") == 0) test_rl_frag_combine(&vol, attr3, attr2, attr1); + else + printf("Frag: No such test '%s'\n", test); + +out: + free(attr1); + free(attr2); + free(attr3); +} + +/** + * test_rl_main - Runlist test: Program start (main) + * @argc: + * @argv: + * + * Description... + * + * Returns: + */ +int test_rl_main(int argc, char *argv[]) +{ + if ((argc == 2) && (strcmp(argv[1], "zero") == 0)) test_rl_zero(); + else if ((argc == 3) && (strcmp(argv[1], "frag") == 0)) test_rl_frag(argv[2]); + else if ((argc == 4) && (strcmp(argv[1], "pure") == 0)) test_rl_pure(argv[2], argv[3]); + else + printf("rl [zero|frag|pure] {args}\n"); + + return 0; +} + +#endif + diff --git a/libntfs-3g/security.c b/libntfs-3g/security.c new file mode 100755 index 0000000..2d5905a --- a/dev/null +++ b/libntfs-3g/security.c @@ -0,0 +1,5167 @@ +/** + * security.c - Handling security/ACLs in NTFS. Originated from the Linux-NTFS project. + * + * Copyright (c) 2004 Anton Altaparmakov + * Copyright (c) 2005-2006 Szabolcs Szakacsits + * Copyright (c) 2006 Yura Pakhuchiy + * Copyright (c) 2007-2009 Jean-Pierre Andre + * + * This program/include file 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/include file 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 (in the main directory of the NTFS-3G + * distribution in the file COPYING); if not, write to the Free Software + * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_STDIO_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_ERRNO_H +#include +#endif +#ifdef HAVE_FCNTL_H +#include +#endif +#ifdef HAVE_SETXATTR +#include +#endif +#ifdef HAVE_SYS_STAT_H +#include +#endif + +#include +#include +#include + +#include "param.h" +#include "types.h" +#include "layout.h" +#include "attrib.h" +#include "index.h" +#include "dir.h" +#include "bitmap.h" +#include "security.h" +#include "acls.h" +#include "cache.h" +#include "misc.h" + +/* + * JPA NTFS constants or structs + * should be moved to layout.h + */ + +#define ALIGN_SDS_BLOCK 0x40000 /* Alignment for a $SDS block */ +#define ALIGN_SDS_ENTRY 16 /* Alignment for a $SDS entry */ +#define STUFFSZ 0x4000 /* unitary stuffing size for $SDS */ +#define FIRST_SECURITY_ID 0x100 /* Lowest security id */ + + /* Mask for attributes which can be forced */ +#define FILE_ATTR_SETTABLE ( FILE_ATTR_READONLY \ + | FILE_ATTR_HIDDEN \ + | FILE_ATTR_SYSTEM \ + | FILE_ATTR_ARCHIVE \ + | FILE_ATTR_TEMPORARY \ + | FILE_ATTR_OFFLINE \ + | FILE_ATTR_NOT_CONTENT_INDEXED ) + +struct SII { /* this is an image of an $SII index entry */ + le16 offs; + le16 size; + le32 fill1; + le16 indexsz; + le16 indexksz; + le16 flags; + le16 fill2; + le32 keysecurid; + + /* did not find official description for the following */ + le32 hash; + le32 securid; + le32 dataoffsl; /* documented as badly aligned */ + le32 dataoffsh; + le32 datasize; +} ; + +struct SDH { /* this is an image of an $SDH index entry */ + le16 offs; + le16 size; + le32 fill1; + le16 indexsz; + le16 indexksz; + le16 flags; + le16 fill2; + le32 keyhash; + le32 keysecurid; + + /* did not find official description for the following */ + le32 hash; + le32 securid; + le32 dataoffsl; + le32 dataoffsh; + le32 datasize; + le32 fill3; + } ; + +/* + * A few useful constants + */ + +static ntfschar sii_stream[] = { const_cpu_to_le16('$'), + const_cpu_to_le16('S'), + const_cpu_to_le16('I'), + const_cpu_to_le16('I'), + const_cpu_to_le16(0) }; +static ntfschar sdh_stream[] = { const_cpu_to_le16('$'), + const_cpu_to_le16('S'), + const_cpu_to_le16('D'), + const_cpu_to_le16('H'), + const_cpu_to_le16(0) }; + +/* + * null SID (S-1-0-0) + */ + +extern const SID *nullsid; + +/* + * The zero GUID. + */ + +static const GUID __zero_guid = { const_cpu_to_le32(0), const_cpu_to_le16(0), + const_cpu_to_le16(0), { 0, 0, 0, 0, 0, 0, 0, 0 } }; +static const GUID *const zero_guid = &__zero_guid; + +/** + * ntfs_guid_is_zero - check if a GUID is zero + * @guid: [IN] guid to check + * + * Return TRUE if @guid is a valid pointer to a GUID and it is the zero GUID + * and FALSE otherwise. + */ +BOOL ntfs_guid_is_zero(const GUID *guid) +{ + return (memcmp(guid, zero_guid, sizeof(*zero_guid))); +} + +/** + * ntfs_guid_to_mbs - convert a GUID to a multi byte string + * @guid: [IN] guid to convert + * @guid_str: [OUT] string in which to return the GUID (optional) + * + * Convert the GUID pointed to by @guid to a multi byte string of the form + * "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX". Therefore, @guid_str (if not NULL) + * needs to be able to store at least 37 bytes. + * + * If @guid_str is not NULL it will contain the converted GUID on return. If + * it is NULL a string will be allocated and this will be returned. The caller + * is responsible for free()ing the string in that case. + * + * On success return the converted string and on failure return NULL with errno + * set to the error code. + */ +char *ntfs_guid_to_mbs(const GUID *guid, char *guid_str) +{ + char *_guid_str; + int res; + + if (!guid) { + errno = EINVAL; + return NULL; + } + _guid_str = guid_str; + if (!_guid_str) { + _guid_str = (char*)ntfs_malloc(37); + if (!_guid_str) + return _guid_str; + } + res = snprintf(_guid_str, 37, + "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", + (unsigned int)le32_to_cpu(guid->data1), + le16_to_cpu(guid->data2), le16_to_cpu(guid->data3), + guid->data4[0], guid->data4[1], + guid->data4[2], guid->data4[3], guid->data4[4], + guid->data4[5], guid->data4[6], guid->data4[7]); + if (res == 36) + return _guid_str; + if (!guid_str) + free(_guid_str); + errno = EINVAL; + return NULL; +} + +/** + * ntfs_sid_to_mbs_size - determine maximum size for the string of a SID + * @sid: [IN] SID for which to determine the maximum string size + * + * Determine the maximum multi byte string size in bytes which is needed to + * store the standard textual representation of the SID pointed to by @sid. + * See ntfs_sid_to_mbs(), below. + * + * On success return the maximum number of bytes needed to store the multi byte + * string and on failure return -1 with errno set to the error code. + */ +int ntfs_sid_to_mbs_size(const SID *sid) +{ + int size, i; + + if (!ntfs_sid_is_valid(sid)) { + errno = EINVAL; + return -1; + } + /* Start with "S-". */ + size = 2; + /* + * Add the SID_REVISION. Hopefully the compiler will optimize this + * away as SID_REVISION is a constant. + */ + for (i = SID_REVISION; i > 0; i /= 10) + size++; + /* Add the "-". */ + size++; + /* + * Add the identifier authority. If it needs to be in decimal, the + * maximum is 2^32-1 = 4294967295 = 10 characters. If it needs to be + * in hexadecimal, then maximum is 0x665544332211 = 14 characters. + */ + if (!sid->identifier_authority.high_part) + size += 10; + else + size += 14; + /* + * Finally, add the sub authorities. For each we have a "-" followed + * by a decimal which can be up to 2^32-1 = 4294967295 = 10 characters. + */ + size += (1 + 10) * sid->sub_authority_count; + /* We need the zero byte at the end, too. */ + size++; + return size * sizeof(char); +} + +/** + * ntfs_sid_to_mbs - convert a SID to a multi byte string + * @sid: [IN] SID to convert + * @sid_str: [OUT] string in which to return the SID (optional) + * @sid_str_size: [IN] size in bytes of @sid_str + * + * Convert the SID pointed to by @sid to its standard textual representation. + * @sid_str (if not NULL) needs to be able to store at least + * ntfs_sid_to_mbs_size() bytes. @sid_str_size is the size in bytes of + * @sid_str if @sid_str is not NULL. + * + * The standard textual representation of the SID is of the form: + * S-R-I-S-S... + * Where: + * - The first "S" is the literal character 'S' identifying the following + * digits as a SID. + * - R is the revision level of the SID expressed as a sequence of digits + * in decimal. + * - I is the 48-bit identifier_authority, expressed as digits in decimal, + * if I < 2^32, or hexadecimal prefixed by "0x", if I >= 2^32. + * - S... is one or more sub_authority values, expressed as digits in + * decimal. + * + * If @sid_str is not NULL it will contain the converted SUID on return. If it + * is NULL a string will be allocated and this will be returned. The caller is + * responsible for free()ing the string in that case. + * + * On success return the converted string and on failure return NULL with errno + * set to the error code. + */ +char *ntfs_sid_to_mbs(const SID *sid, char *sid_str, size_t sid_str_size) +{ + u64 u; + le32 leauth; + char *s; + int i, j, cnt; + + /* + * No need to check @sid if !@sid_str since ntfs_sid_to_mbs_size() will + * check @sid, too. 8 is the minimum SID string size. + */ + if (sid_str && (sid_str_size < 8 || !ntfs_sid_is_valid(sid))) { + errno = EINVAL; + return NULL; + } + /* Allocate string if not provided. */ + if (!sid_str) { + cnt = ntfs_sid_to_mbs_size(sid); + if (cnt < 0) + return NULL; + s = (char*)ntfs_malloc(cnt); + if (!s) + return s; + sid_str = s; + /* So we know we allocated it. */ + sid_str_size = 0; + } else { + s = sid_str; + cnt = sid_str_size; + } + /* Start with "S-R-". */ + i = snprintf(s, cnt, "S-%hhu-", (unsigned char)sid->revision); + if (i < 0 || i >= cnt) + goto err_out; + s += i; + cnt -= i; + /* Add the identifier authority. */ + for (u = i = 0, j = 40; i < 6; i++, j -= 8) + u += (u64)sid->identifier_authority.value[i] << j; + if (!sid->identifier_authority.high_part) + i = snprintf(s, cnt, "%lu", (unsigned long)u); + else + i = snprintf(s, cnt, "0x%llx", (unsigned long long)u); + if (i < 0 || i >= cnt) + goto err_out; + s += i; + cnt -= i; + /* Finally, add the sub authorities. */ + for (j = 0; j < sid->sub_authority_count; j++) { + leauth = sid->sub_authority[j]; + i = snprintf(s, cnt, "-%u", (unsigned int) + le32_to_cpu(leauth)); + if (i < 0 || i >= cnt) + goto err_out; + s += i; + cnt -= i; + } + return sid_str; +err_out: + if (i >= cnt) + i = EMSGSIZE; + else + i = errno; + if (!sid_str_size) + free(sid_str); + errno = i; + return NULL; +} + +/** + * ntfs_generate_guid - generatates a random current guid. + * @guid: [OUT] pointer to a GUID struct to hold the generated guid. + * + * perhaps not a very good random number generator though... + */ +void ntfs_generate_guid(GUID *guid) +{ + unsigned int i; + u8 *p = (u8 *)guid; + + for (i = 0; i < sizeof(GUID); i++) { + p[i] = (u8)(random() & 0xFF); + if (i == 7) + p[7] = (p[7] & 0x0F) | 0x40; + if (i == 8) + p[8] = (p[8] & 0x3F) | 0x80; + } +} + +/** + * ntfs_security_hash - calculate the hash of a security descriptor + * @sd: self-relative security descriptor whose hash to calculate + * @length: size in bytes of the security descritor @sd + * + * Calculate the hash of the self-relative security descriptor @sd of length + * @length bytes. + * + * This hash is used in the $Secure system file as the primary key for the $SDH + * index and is also stored in the header of each security descriptor in the + * $SDS data stream as well as in the index data of both the $SII and $SDH + * indexes. In all three cases it forms part of the SDS_ENTRY_HEADER + * structure. + * + * Return the calculated security hash in little endian. + */ +le32 ntfs_security_hash(const SECURITY_DESCRIPTOR_RELATIVE *sd, const u32 len) +{ + const le32 *pos = (const le32*)sd; + const le32 *end = pos + (len >> 2); + u32 hash = 0; + + while (pos < end) { + hash = le32_to_cpup(pos) + ntfs_rol32(hash, 3); + pos++; + } + return cpu_to_le32(hash); +} + +/* + * Internal read + * copied and pasted from ntfs_fuse_read() and made independent + * of fuse context + */ + +static int ntfs_local_read(ntfs_inode *ni, + ntfschar *stream_name, int stream_name_len, + char *buf, size_t size, off_t offset) +{ + ntfs_attr *na = NULL; + int res, total = 0; + + na = ntfs_attr_open(ni, AT_DATA, stream_name, stream_name_len); + if (!na) { + res = -errno; + goto exit; + } + if ((size_t)offset < (size_t)na->data_size) { + if (offset + size > (size_t)na->data_size) + size = na->data_size - offset; + while (size) { + res = ntfs_attr_pread(na, offset, size, buf); + if ((off_t)res < (off_t)size) + ntfs_log_perror("ntfs_attr_pread partial read " + "(%lld : %lld <> %d)", + (long long)offset, + (long long)size, res); + if (res <= 0) { + res = -errno; + goto exit; + } + size -= res; + offset += res; + total += res; + } + } + res = total; +exit: + if (na) + ntfs_attr_close(na); + return res; +} + + +/* + * Internal write + * copied and pasted from ntfs_fuse_write() and made independent + * of fuse context + */ + +static int ntfs_local_write(ntfs_inode *ni, + ntfschar *stream_name, int stream_name_len, + char *buf, size_t size, off_t offset) +{ + ntfs_attr *na = NULL; + int res, total = 0; + + na = ntfs_attr_open(ni, AT_DATA, stream_name, stream_name_len); + if (!na) { + res = -errno; + goto exit; + } + while (size) { + res = ntfs_attr_pwrite(na, offset, size, buf); + if (res < (s64)size) + ntfs_log_perror("ntfs_attr_pwrite partial write (%lld: " + "%lld <> %d)", (long long)offset, + (long long)size, res); + if (res <= 0) { + res = -errno; + goto exit; + } + size -= res; + offset += res; + total += res; + } + res = total; +exit: + if (na) + ntfs_attr_close(na); + return res; +} + + +/* + * Get the first entry of current index block + * cut and pasted form ntfs_ie_get_first() in index.c + */ + +static INDEX_ENTRY *ntfs_ie_get_first(INDEX_HEADER *ih) +{ + return (INDEX_ENTRY*)((u8*)ih + le32_to_cpu(ih->entries_offset)); +} + +/* + * Stuff a 256KB block into $SDS before writing descriptors + * into the block. + * + * This prevents $SDS from being automatically declared as sparse + * when the second copy of the first security descriptor is written + * 256KB further ahead. + * + * Having $SDS declared as a sparse file is not wrong by itself + * and chkdsk leaves it as a sparse file. It does however complain + * and add a sparse flag (0x0200) into field file_attributes of + * STANDARD_INFORMATION of $Secure. This probably means that a + * sparse attribute (ATTR_IS_SPARSE) is only allowed in sparse + * files (FILE_ATTR_SPARSE_FILE). + * + * Windows normally does not convert to sparse attribute or sparse + * file. Stuffing is just a way to get to the same result. + */ + +static int entersecurity_stuff(ntfs_volume *vol, off_t offs) +{ + int res; + int written; + unsigned long total; + char *stuff; + + res = 0; + total = 0; + stuff = (char*)ntfs_malloc(STUFFSZ); + if (stuff) { + memset(stuff, 0, STUFFSZ); + do { + written = ntfs_local_write(vol->secure_ni, + STREAM_SDS, 4, stuff, STUFFSZ, offs); + if (written == STUFFSZ) { + total += STUFFSZ; + offs += STUFFSZ; + } else { + errno = ENOSPC; + res = -1; + } + } while (!res && (total < ALIGN_SDS_BLOCK)); + free(stuff); + } else { + errno = ENOMEM; + res = -1; + } + return (res); +} + +/* + * Enter a new security descriptor into $Secure (data only) + * it has to be written twice with an offset of 256KB + * + * Should only be called by entersecurityattr() to ensure consistency + * + * Returns zero if sucessful + */ + +static int entersecurity_data(ntfs_volume *vol, + const SECURITY_DESCRIPTOR_RELATIVE *attr, s64 attrsz, + le32 hash, le32 keyid, off_t offs, int gap) +{ + int res; + int written1; + int written2; + char *fullattr; + int fullsz; + SECURITY_DESCRIPTOR_HEADER *phsds; + + res = -1; + fullsz = attrsz + gap + sizeof(SECURITY_DESCRIPTOR_HEADER); + fullattr = (char*)ntfs_malloc(fullsz); + if (fullattr) { + /* + * Clear the gap from previous descriptor + * this could be useful for appending the second + * copy to the end of file. When creating a new + * 256K block, the gap is cleared while writing + * the first copy + */ + if (gap) + memset(fullattr,0,gap); + memcpy(&fullattr[gap + sizeof(SECURITY_DESCRIPTOR_HEADER)], + attr,attrsz); + phsds = (SECURITY_DESCRIPTOR_HEADER*)&fullattr[gap]; + phsds->hash = hash; + phsds->security_id = keyid; + phsds->offset = cpu_to_le64(offs); + phsds->length = cpu_to_le32(fullsz - gap); + written1 = ntfs_local_write(vol->secure_ni, + STREAM_SDS, 4, fullattr, fullsz, + offs - gap); + written2 = ntfs_local_write(vol->secure_ni, + STREAM_SDS, 4, fullattr, fullsz, + offs - gap + ALIGN_SDS_BLOCK); + if ((written1 == fullsz) + && (written2 == written1)) + res = 0; + else + errno = ENOSPC; + free(fullattr); + } else + errno = ENOMEM; + return (res); +} + +/* + * Enter a new security descriptor in $Secure (indexes only) + * + * Should only be called by entersecurityattr() to ensure consistency + * + * Returns zero if sucessful + */ + +static int entersecurity_indexes(ntfs_volume *vol, s64 attrsz, + le32 hash, le32 keyid, off_t offs) +{ + union { + struct { + le32 dataoffsl; + le32 dataoffsh; + } parts; + le64 all; + } realign; + int res; + ntfs_index_context *xsii; + ntfs_index_context *xsdh; + struct SII newsii; + struct SDH newsdh; + + res = -1; + /* enter a new $SII record */ + + xsii = vol->secure_xsii; + ntfs_index_ctx_reinit(xsii); + newsii.offs = const_cpu_to_le16(20); + newsii.size = const_cpu_to_le16(sizeof(struct SII) - 20); + newsii.fill1 = const_cpu_to_le32(0); + newsii.indexsz = const_cpu_to_le16(sizeof(struct SII)); + newsii.indexksz = const_cpu_to_le16(sizeof(SII_INDEX_KEY)); + newsii.flags = const_cpu_to_le16(0); + newsii.fill2 = const_cpu_to_le16(0); + newsii.keysecurid = keyid; + newsii.hash = hash; + newsii.securid = keyid; + realign.all = cpu_to_le64(offs); + newsii.dataoffsh = realign.parts.dataoffsh; + newsii.dataoffsl = realign.parts.dataoffsl; + newsii.datasize = cpu_to_le32(attrsz + + sizeof(SECURITY_DESCRIPTOR_HEADER)); + if (!ntfs_ie_add(xsii,(INDEX_ENTRY*)&newsii)) { + + /* enter a new $SDH record */ + + xsdh = vol->secure_xsdh; + ntfs_index_ctx_reinit(xsdh); + newsdh.offs = const_cpu_to_le16(24); + newsdh.size = const_cpu_to_le16( + sizeof(SECURITY_DESCRIPTOR_HEADER)); + newsdh.fill1 = const_cpu_to_le32(0); + newsdh.indexsz = const_cpu_to_le16( + sizeof(struct SDH)); + newsdh.indexksz = const_cpu_to_le16( + sizeof(SDH_INDEX_KEY)); + newsdh.flags = const_cpu_to_le16(0); + newsdh.fill2 = const_cpu_to_le16(0); + newsdh.keyhash = hash; + newsdh.keysecurid = keyid; + newsdh.hash = hash; + newsdh.securid = keyid; + newsdh.dataoffsh = realign.parts.dataoffsh; + newsdh.dataoffsl = realign.parts.dataoffsl; + newsdh.datasize = cpu_to_le32(attrsz + + sizeof(SECURITY_DESCRIPTOR_HEADER)); + /* special filler value, Windows generally */ + /* fills with 0x00490049, sometimes with zero */ + newsdh.fill3 = const_cpu_to_le32(0x00490049); + if (!ntfs_ie_add(xsdh,(INDEX_ENTRY*)&newsdh)) + res = 0; + } + return (res); +} + +/* + * Enter a new security descriptor in $Secure (data and indexes) + * Returns id of entry, or zero if there is a problem. + * (should not be called for NTFS version < 3.0) + * + * important : calls have to be serialized, however no locking is + * needed while fuse is not multithreaded + */ + +static le32 entersecurityattr(ntfs_volume *vol, + const SECURITY_DESCRIPTOR_RELATIVE *attr, s64 attrsz, + le32 hash) +{ + union { + struct { + le32 dataoffsl; + le32 dataoffsh; + } parts; + le64 all; + } realign; + le32 securid; + le32 keyid; + u32 newkey; + off_t offs; + int gap; + int size; + BOOL found; + struct SII *psii; + INDEX_ENTRY *entry; + INDEX_ENTRY *next; + ntfs_index_context *xsii; + int retries; + ntfs_attr *na; + int olderrno; + + /* find the first available securid beyond the last key */ + /* in $Secure:$SII. This also determines the first */ + /* available location in $Secure:$SDS, as this stream */ + /* is always appended to and the id's are allocated */ + /* in sequence */ + + securid = const_cpu_to_le32(0); + xsii = vol->secure_xsii; + ntfs_index_ctx_reinit(xsii); + offs = size = 0; + keyid = const_cpu_to_le32(-1); + olderrno = errno; + found = !ntfs_index_lookup((char*)&keyid, + sizeof(SII_INDEX_KEY), xsii); + if (!found && (errno != ENOENT)) { + ntfs_log_perror("Inconsistency in index $SII"); + psii = (struct SII*)NULL; + } else { + /* restore errno to avoid misinterpretation */ + errno = olderrno; + entry = xsii->entry; + psii = (struct SII*)xsii->entry; + } + if (psii) { + /* + * Get last entry in block, but must get first one + * one first, as we should already be beyond the + * last one. For some reason the search for the last + * entry sometimes does not return the last block... + * we assume this can only happen in root block + */ + if (xsii->is_in_root) + entry = ntfs_ie_get_first + ((INDEX_HEADER*)&xsii->ir->index); + else + entry = ntfs_ie_get_first + ((INDEX_HEADER*)&xsii->ib->index); + /* + * All index blocks should be at least half full + * so there always is a last entry but one, + * except when creating the first entry in index root. + * This was however found not to be true : chkdsk + * sometimes deletes all the (unused) keys in the last + * index block without rebalancing the tree. + * When this happens, a new search is restarted from + * the smallest key. + */ + keyid = const_cpu_to_le32(0); + retries = 0; + while (entry) { + next = ntfs_index_next(entry,xsii); + if (next) { + psii = (struct SII*)next; + /* save last key and */ + /* available position */ + keyid = psii->keysecurid; + realign.parts.dataoffsh + = psii->dataoffsh; + realign.parts.dataoffsl + = psii->dataoffsl; + offs = le64_to_cpu(realign.all); + size = le32_to_cpu(psii->datasize); + } + entry = next; + if (!entry && !keyid && !retries) { + /* search failed, retry from smallest key */ + ntfs_index_ctx_reinit(xsii); + found = !ntfs_index_lookup((char*)&keyid, + sizeof(SII_INDEX_KEY), xsii); + if (!found && (errno != ENOENT)) { + ntfs_log_perror("Index $SII is broken"); + } else { + /* restore errno */ + errno = olderrno; + entry = xsii->entry; + } + retries++; + } + } + } + if (!keyid) { + /* + * could not find any entry, before creating the first + * entry, make a double check by making sure size of $SII + * is less than needed for one entry + */ + securid = const_cpu_to_le32(0); + na = ntfs_attr_open(vol->secure_ni,AT_INDEX_ROOT,sii_stream,4); + if (na) { + if ((size_t)na->data_size < sizeof(struct SII)) { + ntfs_log_error("Creating the first security_id\n"); + securid = const_cpu_to_le32(FIRST_SECURITY_ID); + } + ntfs_attr_close(na); + } + if (!securid) { + ntfs_log_error("Error creating a security_id\n"); + errno = EIO; + } + } else { + newkey = le32_to_cpu(keyid) + 1; + securid = cpu_to_le32(newkey); + } + /* + * The security attr has to be written twice 256KB + * apart. This implies that offsets like + * 0x40000*odd_integer must be left available for + * the second copy. So align to next block when + * the last byte overflows on a wrong block. + */ + + if (securid) { + gap = (-size) & (ALIGN_SDS_ENTRY - 1); + offs += gap + size; + if ((offs + attrsz + sizeof(SECURITY_DESCRIPTOR_HEADER) - 1) + & ALIGN_SDS_BLOCK) { + offs = ((offs + attrsz + + sizeof(SECURITY_DESCRIPTOR_HEADER) - 1) + | (ALIGN_SDS_BLOCK - 1)) + 1; + } + if (!(offs & (ALIGN_SDS_BLOCK - 1))) + entersecurity_stuff(vol, offs); + /* + * now write the security attr to storage : + * first data, then SII, then SDH + * If failure occurs while writing SDS, data will never + * be accessed through indexes, and will be overwritten + * by the next allocated descriptor + * If failure occurs while writing SII, the id has not + * recorded and will be reallocated later + * If failure occurs while writing SDH, the space allocated + * in SDS or SII will not be reused, an inconsistency + * will persist with no significant consequence + */ + if (entersecurity_data(vol, attr, attrsz, hash, securid, offs, gap) + || entersecurity_indexes(vol, attrsz, hash, securid, offs)) + securid = const_cpu_to_le32(0); + } + /* inode now is dirty, synchronize it all */ + ntfs_index_entry_mark_dirty(vol->secure_xsii); + ntfs_index_ctx_reinit(vol->secure_xsii); + ntfs_index_entry_mark_dirty(vol->secure_xsdh); + ntfs_index_ctx_reinit(vol->secure_xsdh); + NInoSetDirty(vol->secure_ni); + if (ntfs_inode_sync(vol->secure_ni)) + ntfs_log_perror("Could not sync $Secure\n"); + return (securid); +} + +/* + * Find a matching security descriptor in $Secure, + * if none, allocate a new id and write the descriptor to storage + * Returns id of entry, or zero if there is a problem. + * + * important : calls have to be serialized, however no locking is + * needed while fuse is not multithreaded + */ + +static le32 setsecurityattr(ntfs_volume *vol, + const SECURITY_DESCRIPTOR_RELATIVE *attr, s64 attrsz) +{ + struct SDH *psdh; /* this is an image of index (le) */ + union { + struct { + le32 dataoffsl; + le32 dataoffsh; + } parts; + le64 all; + } realign; + BOOL found; + BOOL collision; + size_t size; + size_t rdsize; + s64 offs; + int res; + ntfs_index_context *xsdh; + char *oldattr; + SDH_INDEX_KEY key; + INDEX_ENTRY *entry; + le32 securid; + le32 hash; + int olderrno; + + hash = ntfs_security_hash(attr,attrsz); + oldattr = (char*)NULL; + securid = const_cpu_to_le32(0); + res = 0; + xsdh = vol->secure_xsdh; + if (vol->secure_ni && xsdh && !vol->secure_reentry++) { + ntfs_index_ctx_reinit(xsdh); + /* + * find the nearest key as (hash,0) + * (do not search for partial key : in case of collision, + * it could return a key which is not the first one which + * collides) + */ + key.hash = hash; + key.security_id = const_cpu_to_le32(0); + olderrno = errno; + found = !ntfs_index_lookup((char*)&key, + sizeof(SDH_INDEX_KEY), xsdh); + if (!found && (errno != ENOENT)) + ntfs_log_perror("Inconsistency in index $SDH"); + else { + /* restore errno to avoid misinterpretation */ + errno = olderrno; + entry = xsdh->entry; + found = FALSE; + /* + * lookup() may return a node with no data, + * if so get next + */ + if (entry->ie_flags & INDEX_ENTRY_END) + entry = ntfs_index_next(entry,xsdh); + do { + collision = FALSE; + psdh = (struct SDH*)entry; + if (psdh) + size = (size_t) le32_to_cpu(psdh->datasize) + - sizeof(SECURITY_DESCRIPTOR_HEADER); + else size = 0; + /* if hash is not the same, the key is not present */ + if (psdh && (size > 0) + && (psdh->keyhash == hash)) { + /* if hash is the same */ + /* check the whole record */ + realign.parts.dataoffsh = psdh->dataoffsh; + realign.parts.dataoffsl = psdh->dataoffsl; + offs = le64_to_cpu(realign.all) + + sizeof(SECURITY_DESCRIPTOR_HEADER); + oldattr = (char*)ntfs_malloc(size); + if (oldattr) { + rdsize = ntfs_local_read( + vol->secure_ni, + STREAM_SDS, 4, + oldattr, size, offs); + found = (rdsize == size) + && !memcmp(oldattr,attr,size); + free(oldattr); + /* if the records do not compare */ + /* (hash collision), try next one */ + if (!found) { + entry = ntfs_index_next( + entry,xsdh); + collision = TRUE; + } + } else + res = ENOMEM; + } + } while (collision && entry); + if (found) + securid = psdh->keysecurid; + else { + if (res) { + errno = res; + securid = const_cpu_to_le32(0); + } else { + /* + * no matching key : + * have to build a new one + */ + securid = entersecurityattr(vol, + attr, attrsz, hash); + } + } + } + } + if (--vol->secure_reentry) + ntfs_log_perror("Reentry error, check no multithreading\n"); + return (securid); +} + + +/* + * Update the security descriptor of a file + * Either as an attribute (complying with pre v3.x NTFS version) + * or, when possible, as an entry in $Secure (for NTFS v3.x) + * + * returns 0 if success + */ + +static int update_secur_descr(ntfs_volume *vol, + char *newattr, ntfs_inode *ni) +{ + int newattrsz; + int written; + int res; + ntfs_attr *na; + + newattrsz = ntfs_attr_size(newattr); + +#if !FORCE_FORMAT_v1x + if ((vol->major_ver < 3) || !vol->secure_ni) { +#endif + + /* update for NTFS format v1.x */ + + /* update the old security attribute */ + na = ntfs_attr_open(ni, AT_SECURITY_DESCRIPTOR, AT_UNNAMED, 0); + if (na) { + /* resize attribute */ + res = ntfs_attr_truncate(na, (s64) newattrsz); + /* overwrite value */ + if (!res) { + written = (int)ntfs_attr_pwrite(na, (s64) 0, + (s64) newattrsz, newattr); + if (written != newattrsz) { + ntfs_log_error("Failed to update " + "a v1.x security descriptor\n"); + errno = EIO; + res = -1; + } + } + + ntfs_attr_close(na); + /* if old security attribute was found, also */ + /* truncate standard information attribute to v1.x */ + /* this is needed when security data is wanted */ + /* as v1.x though volume is formatted for v3.x */ + na = ntfs_attr_open(ni, AT_STANDARD_INFORMATION, + AT_UNNAMED, 0); + if (na) { + clear_nino_flag(ni, v3_Extensions); + /* + * Truncating the record does not sweep extensions + * from copy in memory. Clear security_id to be safe + */ + ni->security_id = const_cpu_to_le32(0); + res = ntfs_attr_truncate(na, (s64)48); + ntfs_attr_close(na); + clear_nino_flag(ni, v3_Extensions); + } + } else { + /* + * insert the new security attribute if there + * were none + */ + res = ntfs_attr_add(ni, AT_SECURITY_DESCRIPTOR, + AT_UNNAMED, 0, (u8*)newattr, + (s64) newattrsz); + } +#if !FORCE_FORMAT_v1x + } else { + + /* update for NTFS format v3.x */ + + le32 securid; + + securid = setsecurityattr(vol, + (const SECURITY_DESCRIPTOR_RELATIVE*)newattr, + (s64)newattrsz); + if (securid) { + na = ntfs_attr_open(ni, AT_STANDARD_INFORMATION, + AT_UNNAMED, 0); + if (na) { + res = 0; + if (!test_nino_flag(ni, v3_Extensions)) { + /* expand standard information attribute to v3.x */ + res = ntfs_attr_truncate(na, + (s64)sizeof(STANDARD_INFORMATION)); + ni->owner_id = const_cpu_to_le32(0); + ni->quota_charged = const_cpu_to_le64(0); + ni->usn = const_cpu_to_le64(0); + ntfs_attr_remove(ni, + AT_SECURITY_DESCRIPTOR, + AT_UNNAMED, 0); + } + set_nino_flag(ni, v3_Extensions); + ni->security_id = securid; + ntfs_attr_close(na); + } else { + ntfs_log_error("Failed to update " + "standard informations\n"); + errno = EIO; + res = -1; + } + } else + res = -1; + } +#endif + + /* mark node as dirty */ + NInoSetDirty(ni); + ntfs_inode_sync(ni); /* useful ? */ + return (res); +} + +/* + * Upgrade the security descriptor of a file + * This is intended to allow graceful upgrades for files which + * were created in previous versions, with a security attributes + * and no security id. + * + * It will allocate a security id and replace the individual + * security attribute by a reference to the global one + * + * Special files are not upgraded (currently / and files in + * directories /$*) + * + * Though most code is similar to update_secur_desc() it has + * been kept apart to facilitate the further processing of + * special cases or even to remove it if found dangerous. + * + * returns 0 if success, + * 1 if not upgradable. This is not an error. + * -1 if there is a problem + */ + +static int upgrade_secur_desc(ntfs_volume *vol, + const char *attr, ntfs_inode *ni) +{ + int attrsz; + int res; + le32 securid; + ntfs_attr *na; + + /* + * upgrade requires NTFS format v3.x + * also refuse upgrading for special files + * whose number is less than FILE_first_user + */ + + if ((vol->major_ver >= 3) + && (ni->mft_no >= FILE_first_user)) { + attrsz = ntfs_attr_size(attr); + securid = setsecurityattr(vol, + (const SECURITY_DESCRIPTOR_RELATIVE*)attr, + (s64)attrsz); + if (securid) { + na = ntfs_attr_open(ni, AT_STANDARD_INFORMATION, + AT_UNNAMED, 0); + if (na) { + res = 0; + /* expand standard information attribute to v3.x */ + res = ntfs_attr_truncate(na, + (s64)sizeof(STANDARD_INFORMATION)); + ni->owner_id = const_cpu_to_le32(0); + ni->quota_charged = const_cpu_to_le64(0); + ni->usn = const_cpu_to_le64(0); + ntfs_attr_remove(ni, AT_SECURITY_DESCRIPTOR, + AT_UNNAMED, 0); + set_nino_flag(ni, v3_Extensions); + ni->security_id = securid; + ntfs_attr_close(na); + } else { + ntfs_log_error("Failed to upgrade " + "standard informations\n"); + errno = EIO; + res = -1; + } + } else + res = -1; + /* mark node as dirty */ + NInoSetDirty(ni); + ntfs_inode_sync(ni); /* useful ? */ + } else + res = 1; + + return (res); +} + +/* + * Optional simplified checking of group membership + * + * This only takes into account the groups defined in + * /etc/group at initialization time. + * It does not take into account the groups dynamically set by + * setgroups() nor the changes in /etc/group since initialization + * + * This optional method could be useful if standard checking + * leads to a performance concern. + * + * Should not be called for user root, however the group may be root + * + */ + +static BOOL staticgroupmember(struct SECURITY_CONTEXT *scx, uid_t uid, gid_t gid) +{ + BOOL ingroup; + int grcnt; + gid_t *groups; + struct MAPPING *user; + + ingroup = FALSE; + if (uid) { + user = scx->mapping[MAPUSERS]; + while (user && ((uid_t)user->xid != uid)) + user = user->next; + if (user) { + groups = user->groups; + grcnt = user->grcnt; + while ((--grcnt >= 0) && (groups[grcnt] != gid)) { } + ingroup = (grcnt >= 0); + } + } + return (ingroup); +} + + +/* + * Check whether current thread owner is member of file group + * + * Should not be called for user root, however the group may be root + * + * As indicated by Miklos Szeredi : + * + * The group list is available in + * + * /proc/$PID/task/$TID/status + * + * and fuse supplies TID in get_fuse_context()->pid. The only problem is + * finding out PID, for which I have no good solution, except to iterate + * through all processes. This is rather slow, but may be speeded up + * with caching and heuristics (for single threaded programs PID = TID). + * + * The following implementation gets the group list from + * /proc/$TID/task/$TID/status which apparently exists and + * contains the same data. + */ + +static BOOL groupmember(struct SECURITY_CONTEXT *scx, uid_t uid, gid_t gid) +{ + static char key[] = "\nGroups:"; + char buf[BUFSZ+1]; + char filename[64]; + enum { INKEY, INSEP, INNUM, INEND } state; + int fd; + char c; + int matched; + BOOL ismember; + int got; + char *p; + gid_t grp; + pid_t tid; + + if (scx->vol->secure_flags & (1 << SECURITY_STATICGRPS)) + ismember = staticgroupmember(scx, uid, gid); + else { + ismember = FALSE; /* default return */ + tid = scx->tid; + sprintf(filename,"/proc/%u/task/%u/status",tid,tid); + fd = open(filename,O_RDONLY); + if (fd >= 0) { + got = read(fd, buf, BUFSZ); + buf[got] = 0; + state = INKEY; + matched = 0; + p = buf; + grp = 0; + /* + * A simple automaton to process lines like + * Groups: 14 500 513 + */ + do { + c = *p++; + if (!c) { + /* refill buffer */ + got = read(fd, buf, BUFSZ); + buf[got] = 0; + p = buf; + c = *p++; /* 0 at end of file */ + } + switch (state) { + case INKEY : + if (key[matched] == c) { + if (!key[++matched]) + state = INSEP; + } else + if (key[0] == c) + matched = 1; + else + matched = 0; + break; + case INSEP : + if ((c >= '0') && (c <= '9')) { + grp = c - '0'; + state = INNUM; + } else + if ((c != ' ') && (c != '\t')) + state = INEND; + break; + case INNUM : + if ((c >= '0') && (c <= '9')) + grp = grp*10 + c - '0'; + else { + ismember = (grp == gid); + if ((c != ' ') && (c != '\t')) + state = INEND; + else + state = INSEP; + } + default : + break; + } + } while (!ismember && c && (state != INEND)); + close(fd); + if (!c) + ntfs_log_error("No group record found in %s\n",filename); + } else + ntfs_log_error("Could not open %s\n",filename); + } + return (ismember); +} + +/* + * Cacheing is done two-way : + * - from uid, gid and perm to securid (CACHED_SECURID) + * - from a securid to uid, gid and perm (CACHED_PERMISSIONS) + * + * CACHED_SECURID data is kept in a most-recent-first list + * which should not be too long to be efficient. Its optimal + * size is depends on usage and is hard to determine. + * + * CACHED_PERMISSIONS data is kept in a two-level indexed array. It + * is optimal at the expense of storage. Use of a most-recent-first + * list would save memory and provide similar performances for + * standard usage, but not for file servers with too many file + * owners + * + * CACHED_PERMISSIONS_LEGACY is a special case for CACHED_PERMISSIONS + * for legacy directories which were not allocated a security_id + * it is organized in a most-recent-first list. + * + * In main caches, data is never invalidated, as the meaning of + * a security_id only changes when user mapping is changed, which + * current implies remounting. However returned entries may be + * overwritten at next update, so data has to be copied elsewhere + * before another cache update is made. + * In legacy cache, data has to be invalidated when protection is + * changed. + * + * Though the same data may be found in both list, they + * must be kept separately : the interpretation of ACL + * in both direction are approximations which could be non + * reciprocal for some configuration of the user mapping data + * + * During the process of recompiling ntfs-3g from a tgz archive, + * security processing added 7.6% to the cpu time used by ntfs-3g + * and 30% if the cache is disabled. + */ + +static struct PERMISSIONS_CACHE *create_caches(struct SECURITY_CONTEXT *scx, + u32 securindex) +{ + struct PERMISSIONS_CACHE *cache; + unsigned int index1; + unsigned int i; + + cache = (struct PERMISSIONS_CACHE*)NULL; + /* create the first permissions blocks */ + index1 = securindex >> CACHE_PERMISSIONS_BITS; + cache = (struct PERMISSIONS_CACHE*) + ntfs_malloc(sizeof(struct PERMISSIONS_CACHE) + + index1*sizeof(struct CACHED_PERMISSIONS*)); + if (cache) { + cache->head.last = index1; + cache->head.p_reads = 0; + cache->head.p_hits = 0; + cache->head.p_writes = 0; + *scx->pseccache = cache; + for (i=0; i<=index1; i++) + cache->cachetable[i] + = (struct CACHED_PERMISSIONS*)NULL; + } + return (cache); +} + +/* + * Free memory used by caches + * The only purpose is to facilitate the detection of memory leaks + */ + +static void free_caches(struct SECURITY_CONTEXT *scx) +{ + unsigned int index1; + struct PERMISSIONS_CACHE *pseccache; + + pseccache = *scx->pseccache; + if (pseccache) { + for (index1=0; index1<=pseccache->head.last; index1++) + if (pseccache->cachetable[index1]) { +#if POSIXACLS + struct CACHED_PERMISSIONS *cacheentry; + unsigned int index2; + + for (index2=0; index2<(1<< CACHE_PERMISSIONS_BITS); index2++) { + cacheentry = &pseccache->cachetable[index1][index2]; + if (cacheentry->valid + && cacheentry->pxdesc) + free(cacheentry->pxdesc); + } +#endif + free(pseccache->cachetable[index1]); + } + free(pseccache); + } +} + +static int compare(const struct CACHED_SECURID *cached, + const struct CACHED_SECURID *item) +{ +#if POSIXACLS + size_t csize; + size_t isize; + + /* only compare data and sizes */ + csize = (cached->variable ? + sizeof(struct POSIX_ACL) + + (((struct POSIX_SECURITY*)cached->variable)->acccnt + + ((struct POSIX_SECURITY*)cached->variable)->defcnt) + *sizeof(struct POSIX_ACE) : + 0); + isize = (item->variable ? + sizeof(struct POSIX_ACL) + + (((struct POSIX_SECURITY*)item->variable)->acccnt + + ((struct POSIX_SECURITY*)item->variable)->defcnt) + *sizeof(struct POSIX_ACE) : + 0); + return ((cached->uid != item->uid) + || (cached->gid != item->gid) + || (cached->dmode != item->dmode) + || (csize != isize) + || (csize + && isize + && memcmp(&((struct POSIX_SECURITY*)cached->variable)->acl, + &((struct POSIX_SECURITY*)item->variable)->acl, csize))); +#else + return ((cached->uid != item->uid) + || (cached->gid != item->gid) + || (cached->dmode != item->dmode)); +#endif +} + +static int leg_compare(const struct CACHED_PERMISSIONS_LEGACY *cached, + const struct CACHED_PERMISSIONS_LEGACY *item) +{ + return (cached->mft_no != item->mft_no); +} + +/* + * Resize permission cache table + * do not call unless resizing is needed + * + * If allocation fails, the cache size is not updated + * Lack of memory is not considered as an error, the cache is left + * consistent and errno is not set. + */ + +static void resize_cache(struct SECURITY_CONTEXT *scx, + u32 securindex) +{ + struct PERMISSIONS_CACHE *oldcache; + struct PERMISSIONS_CACHE *newcache; + int newcnt; + int oldcnt; + unsigned int index1; + unsigned int i; + + oldcache = *scx->pseccache; + index1 = securindex >> CACHE_PERMISSIONS_BITS; + newcnt = index1 + 1; + if (newcnt <= ((CACHE_PERMISSIONS_SIZE + + (1 << CACHE_PERMISSIONS_BITS) + - 1) >> CACHE_PERMISSIONS_BITS)) { + /* expand cache beyond current end, do not use realloc() */ + /* to avoid losing data when there is no more memory */ + oldcnt = oldcache->head.last + 1; + newcache = (struct PERMISSIONS_CACHE*) + ntfs_malloc( + sizeof(struct PERMISSIONS_CACHE) + + (newcnt - 1)*sizeof(struct CACHED_PERMISSIONS*)); + if (newcache) { + memcpy(newcache,oldcache, + sizeof(struct PERMISSIONS_CACHE) + + (oldcnt - 1)*sizeof(struct CACHED_PERMISSIONS*)); + free(oldcache); + /* mark new entries as not valid */ + for (i=newcache->head.last+1; i<=index1; i++) + newcache->cachetable[i] + = (struct CACHED_PERMISSIONS*)NULL; + newcache->head.last = index1; + *scx->pseccache = newcache; + } + } +} + +/* + * Enter uid, gid and mode into cache, if possible + * + * returns the updated or created cache entry, + * or NULL if not possible (typically if there is no + * security id associated) + */ + +#if POSIXACLS +static struct CACHED_PERMISSIONS *enter_cache(struct SECURITY_CONTEXT *scx, + ntfs_inode *ni, uid_t uid, gid_t gid, + struct POSIX_SECURITY *pxdesc) +#else +static struct CACHED_PERMISSIONS *enter_cache(struct SECURITY_CONTEXT *scx, + ntfs_inode *ni, uid_t uid, gid_t gid, mode_t mode) +#endif +{ + struct CACHED_PERMISSIONS *cacheentry; + struct CACHED_PERMISSIONS *cacheblock; + struct PERMISSIONS_CACHE *pcache; + u32 securindex; +#if POSIXACLS + int pxsize; + struct POSIX_SECURITY *pxcached; +#endif + unsigned int index1; + unsigned int index2; + int i; + + /* cacheing is only possible if a security_id has been defined */ + if (test_nino_flag(ni, v3_Extensions) + && ni->security_id) { + /* + * Immediately test the most frequent situation + * where the entry exists + */ + securindex = le32_to_cpu(ni->security_id); + index1 = securindex >> CACHE_PERMISSIONS_BITS; + index2 = securindex & ((1 << CACHE_PERMISSIONS_BITS) - 1); + pcache = *scx->pseccache; + if (pcache + && (pcache->head.last >= index1) + && pcache->cachetable[index1]) { + cacheentry = &pcache->cachetable[index1][index2]; + cacheentry->uid = uid; + cacheentry->gid = gid; +#if POSIXACLS + if (cacheentry->valid && cacheentry->pxdesc) + free(cacheentry->pxdesc); + if (pxdesc) { + pxsize = sizeof(struct POSIX_SECURITY) + + (pxdesc->acccnt + pxdesc->defcnt)*sizeof(struct POSIX_ACE); + pxcached = (struct POSIX_SECURITY*)malloc(pxsize); + if (pxcached) { + memcpy(pxcached, pxdesc, pxsize); + cacheentry->pxdesc = pxcached; + } else { + cacheentry->valid = 0; + cacheentry = (struct CACHED_PERMISSIONS*)NULL; + } + cacheentry->mode = pxdesc->mode & 07777; + } else + cacheentry->pxdesc = (struct POSIX_SECURITY*)NULL; +#else + cacheentry->mode = mode & 07777; +#endif + cacheentry->inh_fileid = const_cpu_to_le32(0); + cacheentry->inh_dirid = const_cpu_to_le32(0); + cacheentry->valid = 1; + pcache->head.p_writes++; + } else { + if (!pcache) { + /* create the first cache block */ + pcache = create_caches(scx, securindex); + } else { + if (index1 > pcache->head.last) { + resize_cache(scx, securindex); + pcache = *scx->pseccache; + } + } + /* allocate block, if cache table was allocated */ + if (pcache && (index1 <= pcache->head.last)) { + cacheblock = (struct CACHED_PERMISSIONS*) + malloc(sizeof(struct CACHED_PERMISSIONS) + << CACHE_PERMISSIONS_BITS); + pcache->cachetable[index1] = cacheblock; + for (i=0; i<(1 << CACHE_PERMISSIONS_BITS); i++) + cacheblock[i].valid = 0; + cacheentry = &cacheblock[index2]; + if (cacheentry) { + cacheentry->uid = uid; + cacheentry->gid = gid; +#if POSIXACLS + if (pxdesc) { + pxsize = sizeof(struct POSIX_SECURITY) + + (pxdesc->acccnt + pxdesc->defcnt)*sizeof(struct POSIX_ACE); + pxcached = (struct POSIX_SECURITY*)malloc(pxsize); + if (pxcached) { + memcpy(pxcached, pxdesc, pxsize); + cacheentry->pxdesc = pxcached; + } else { + cacheentry->valid = 0; + cacheentry = (struct CACHED_PERMISSIONS*)NULL; + } + cacheentry->mode = pxdesc->mode & 07777; + } else + cacheentry->pxdesc = (struct POSIX_SECURITY*)NULL; +#else + cacheentry->mode = mode & 07777; +#endif + cacheentry->inh_fileid = const_cpu_to_le32(0); + cacheentry->inh_dirid = const_cpu_to_le32(0); + cacheentry->valid = 1; + pcache->head.p_writes++; + } + } else + cacheentry = (struct CACHED_PERMISSIONS*)NULL; + } + } else { + cacheentry = (struct CACHED_PERMISSIONS*)NULL; +#if CACHE_LEGACY_SIZE + if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) { + struct CACHED_PERMISSIONS_LEGACY wanted; + struct CACHED_PERMISSIONS_LEGACY *legacy; + + wanted.perm.uid = uid; + wanted.perm.gid = gid; +#if POSIXACLS + wanted.perm.mode = pxdesc->mode & 07777; + wanted.perm.inh_fileid = const_cpu_to_le32(0); + wanted.perm.inh_dirid = const_cpu_to_le32(0); + wanted.mft_no = ni->mft_no; + wanted.variable = (void*)pxdesc; + wanted.varsize = sizeof(struct POSIX_SECURITY) + + (pxdesc->acccnt + pxdesc->defcnt)*sizeof(struct POSIX_ACE); +#else + wanted.perm.mode = mode & 07777; + wanted.perm.inh_fileid = const_cpu_to_le32(0); + wanted.perm.inh_dirid = const_cpu_to_le32(0); + wanted.mft_no = ni->mft_no; + wanted.variable = (void*)NULL; + wanted.varsize = 0; +#endif + legacy = (struct CACHED_PERMISSIONS_LEGACY*)ntfs_enter_cache( + scx->vol->legacy_cache, GENERIC(&wanted), + (cache_compare)leg_compare); + if (legacy) { + cacheentry = &legacy->perm; +#if POSIXACLS + /* + * give direct access to the cached pxdesc + * in the permissions structure + */ + cacheentry->pxdesc = legacy->variable; +#endif + } + } +#endif + } + return (cacheentry); +} + +/* + * Fetch owner, group and permission of a file, if cached + * + * Beware : do not use the returned entry after a cache update : + * the cache may be relocated making the returned entry meaningless + * + * returns the cache entry, or NULL if not available + */ + +static struct CACHED_PERMISSIONS *fetch_cache(struct SECURITY_CONTEXT *scx, + ntfs_inode *ni) +{ + struct CACHED_PERMISSIONS *cacheentry; + struct PERMISSIONS_CACHE *pcache; + u32 securindex; + unsigned int index1; + unsigned int index2; + + /* cacheing is only possible if a security_id has been defined */ + cacheentry = (struct CACHED_PERMISSIONS*)NULL; + if (test_nino_flag(ni, v3_Extensions) + && (ni->security_id)) { + securindex = le32_to_cpu(ni->security_id); + index1 = securindex >> CACHE_PERMISSIONS_BITS; + index2 = securindex & ((1 << CACHE_PERMISSIONS_BITS) - 1); + pcache = *scx->pseccache; + if (pcache + && (pcache->head.last >= index1) + && pcache->cachetable[index1]) { + cacheentry = &pcache->cachetable[index1][index2]; + /* reject if entry is not valid */ + if (!cacheentry->valid) + cacheentry = (struct CACHED_PERMISSIONS*)NULL; + else + pcache->head.p_hits++; + if (pcache) + pcache->head.p_reads++; + } + } +#if CACHE_LEGACY_SIZE + else { + cacheentry = (struct CACHED_PERMISSIONS*)NULL; + if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) { + struct CACHED_PERMISSIONS_LEGACY wanted; + struct CACHED_PERMISSIONS_LEGACY *legacy; + + wanted.mft_no = ni->mft_no; + wanted.variable = (void*)NULL; + wanted.varsize = 0; + legacy = (struct CACHED_PERMISSIONS_LEGACY*)ntfs_fetch_cache( + scx->vol->legacy_cache, GENERIC(&wanted), + (cache_compare)leg_compare); + if (legacy) cacheentry = &legacy->perm; + } + } +#endif +#if POSIXACLS + if (cacheentry && !cacheentry->pxdesc) { + ntfs_log_error("No Posix descriptor in cache\n"); + cacheentry = (struct CACHED_PERMISSIONS*)NULL; + } +#endif + return (cacheentry); +} + +/* + * Retrieve a security attribute from $Secure + */ + +static char *retrievesecurityattr(ntfs_volume *vol, SII_INDEX_KEY id) +{ + struct SII *psii; + union { + struct { + le32 dataoffsl; + le32 dataoffsh; + } parts; + le64 all; + } realign; + int found; + size_t size; + size_t rdsize; + s64 offs; + ntfs_inode *ni; + ntfs_index_context *xsii; + char *securattr; + + securattr = (char*)NULL; + ni = vol->secure_ni; + xsii = vol->secure_xsii; + if (ni && xsii) { + ntfs_index_ctx_reinit(xsii); + found = + !ntfs_index_lookup((char*)&id, + sizeof(SII_INDEX_KEY), xsii); + if (found) { + psii = (struct SII*)xsii->entry; + size = + (size_t) le32_to_cpu(psii->datasize) + - sizeof(SECURITY_DESCRIPTOR_HEADER); + /* work around bad alignment problem */ + realign.parts.dataoffsh = psii->dataoffsh; + realign.parts.dataoffsl = psii->dataoffsl; + offs = le64_to_cpu(realign.all) + + sizeof(SECURITY_DESCRIPTOR_HEADER); + + securattr = (char*)ntfs_malloc(size); + if (securattr) { + rdsize = ntfs_local_read( + ni, STREAM_SDS, 4, + securattr, size, offs); + if ((rdsize != size) + || !ntfs_valid_descr(securattr, + rdsize)) { + /* error to be logged by caller */ + free(securattr); + securattr = (char*)NULL; + } + } + } else + if (errno != ENOENT) + ntfs_log_perror("Inconsistency in index $SII"); + } + if (!securattr) { + ntfs_log_error("Failed to retrieve a security descriptor\n"); + errno = EIO; + } + return (securattr); +} + +/* + * Get the security descriptor associated to a file + * + * Either : + * - read the security descriptor attribute (v1.x format) + * - or find the descriptor in $Secure:$SDS (v3.x format) + * + * in both case, sanity checks are done on the attribute and + * the descriptor can be assumed safe + * + * The returned descriptor is dynamically allocated and has to be freed + */ + +static char *getsecurityattr(ntfs_volume *vol, ntfs_inode *ni) +{ + SII_INDEX_KEY securid; + char *securattr; + s64 readallsz; + + /* + * Warning : in some situations, after fixing by chkdsk, + * v3_Extensions are marked present (long standard informations) + * with a default security descriptor inserted in an + * attribute + */ + if (test_nino_flag(ni, v3_Extensions) + && vol->secure_ni && ni->security_id) { + /* get v3.x descriptor in $Secure */ + securid.security_id = ni->security_id; + securattr = retrievesecurityattr(vol,securid); + if (!securattr) + ntfs_log_error("Bad security descriptor for 0x%lx\n", + (long)le32_to_cpu(ni->security_id)); + } else { + /* get v1.x security attribute */ + readallsz = 0; + securattr = ntfs_attr_readall(ni, AT_SECURITY_DESCRIPTOR, + AT_UNNAMED, 0, &readallsz); + if (securattr && !ntfs_valid_descr(securattr, readallsz)) { + ntfs_log_error("Bad security descriptor for inode %lld\n", + (long long)ni->mft_no); + free(securattr); + securattr = (char*)NULL; + } + } + if (!securattr) { + /* + * in some situations, there is no security + * descriptor, and chkdsk does not detect or fix + * anything. This could be a normal situation. + * When this happens, simulate a descriptor with + * minimum rights, so that a real descriptor can + * be created by chown or chmod + */ + ntfs_log_error("No security descriptor found for inode %lld\n", + (long long)ni->mft_no); + securattr = ntfs_build_descr(0, 0, adminsid, adminsid); + } + return (securattr); +} + +#if POSIXACLS + +/* + * Determine which access types to a file are allowed + * according to the relation of current process to the file + * + * Do not call if default_permissions is set + */ + +static int access_check_posix(struct SECURITY_CONTEXT *scx, + struct POSIX_SECURITY *pxdesc, mode_t request, + uid_t uid, gid_t gid) +{ + struct POSIX_ACE *pxace; + int userperms; + int groupperms; + int mask; + BOOL somegroup; + BOOL needgroups; + mode_t perms; + int i; + + perms = pxdesc->mode; + /* owner and root access */ + if (!scx->uid || (uid == scx->uid)) { + if (!scx->uid) { + /* root access if owner or other execution */ + if (perms & 0101) + perms = 07777; + else { + /* root access if some group execution */ + groupperms = 0; + mask = 7; + for (i=pxdesc->acccnt-1; i>=0 ; i--) { + pxace = &pxdesc->acl.ace[i]; + switch (pxace->tag) { + case POSIX_ACL_USER_OBJ : + case POSIX_ACL_GROUP_OBJ : + case POSIX_ACL_GROUP : + groupperms |= pxace->perms; + break; + case POSIX_ACL_MASK : + mask = pxace->perms & 7; + break; + default : + break; + } + } + perms = (groupperms & mask & 1) | 6; + } + } else + perms &= 07700; + } else { + /* + * analyze designated users, get mask + * and identify whether we need to check + * the group memberships. The groups are + * not needed when all groups have the + * same permissions as other for the + * requested modes. + */ + userperms = -1; + groupperms = -1; + needgroups = FALSE; + mask = 7; + for (i=pxdesc->acccnt-1; i>=0 ; i--) { + pxace = &pxdesc->acl.ace[i]; + switch (pxace->tag) { + case POSIX_ACL_USER : + if ((uid_t)pxace->id == scx->uid) + userperms = pxace->perms; + break; + case POSIX_ACL_MASK : + mask = pxace->perms & 7; + break; + case POSIX_ACL_GROUP_OBJ : + case POSIX_ACL_GROUP : + if (((pxace->perms & mask) ^ perms) + & (request >> 6) & 7) + needgroups = TRUE; + break; + default : + break; + } + } + /* designated users */ + if (userperms >= 0) + perms = (perms & 07000) + (userperms & mask); + else if (!needgroups) + perms &= 07007; + else { + /* owning group */ + if (!(~(perms >> 3) & request & mask) + && ((gid == scx->gid) + || groupmember(scx, scx->uid, gid))) + perms &= 07070; + else { + /* other groups */ + groupperms = -1; + somegroup = FALSE; + for (i=pxdesc->acccnt-1; i>=0 ; i--) { + pxace = &pxdesc->acl.ace[i]; + if ((pxace->tag == POSIX_ACL_GROUP) + && groupmember(scx, uid, pxace->id)) { + if (!(~pxace->perms & request & mask)) + groupperms = pxace->perms; + somegroup = TRUE; + } + } + if (groupperms >= 0) + perms = (perms & 07000) + (groupperms & mask); + else + if (somegroup) + perms = 0; + else + perms &= 07007; + } + } + } + return (perms); +} + +/* + * Get permissions to access a file + * Takes into account the relation of user to file (owner, group, ...) + * Do no use as mode of the file + * Do no call if default_permissions is set + * + * returns -1 if there is a problem + */ +#if 0 +static int ntfs_get_perm(struct SECURITY_CONTEXT *scx, + ntfs_inode * ni, mode_t request) +{ + const SECURITY_DESCRIPTOR_RELATIVE *phead; + const struct CACHED_PERMISSIONS *cached; + char *securattr; + const SID *usid; /* owner of file/directory */ + const SID *gsid; /* group of file/directory */ + uid_t uid; + gid_t gid; + int perm; + BOOL isdir; + struct POSIX_SECURITY *pxdesc; + + if (!scx->mapping[MAPUSERS]) + perm = 07777; + else { + /* check whether available in cache */ + cached = fetch_cache(scx,ni); + if (cached) { + uid = cached->uid; + gid = cached->gid; + perm = access_check_posix(scx,cached->pxdesc,request,uid,gid); + } else { + perm = 0; /* default to no permission */ + isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) + != const_cpu_to_le16(0); + securattr = getsecurityattr(scx->vol, ni); + if (securattr) { + phead = (const SECURITY_DESCRIPTOR_RELATIVE*) + securattr; + gsid = (const SID*)& + securattr[le32_to_cpu(phead->group)]; + gid = ntfs_find_group(scx->mapping[MAPGROUPS],gsid); +#if OWNERFROMACL + usid = ntfs_acl_owner(securattr); + pxdesc = ntfs_build_permissions_posix(scx->mapping,securattr, + usid, gsid, isdir); + if (pxdesc) + perm = pxdesc->mode & 07777; + else + perm = -1; + uid = ntfs_find_user(scx->mapping[MAPUSERS],usid); +#else + usid = (const SID*)& + securattr[le32_to_cpu(phead->owner)]; + pxdesc = ntfs_build_permissions_posix(scx,securattr, + usid, gsid, isdir); + if (pxdesc) + perm = pxdesc->mode & 07777; + else + perm = -1; + if (!perm && ntfs_same_sid(usid, adminsid)) { + uid = find_tenant(scx, securattr); + if (uid) + perm = 0700; + } else + uid = ntfs_find_user(scx->mapping[MAPUSERS],usid); +#endif + /* + * Create a security id if there were none + * and upgrade option is selected + */ + if (!test_nino_flag(ni, v3_Extensions) + && (perm >= 0) + && (scx->vol->secure_flags + & (1 << SECURITY_ADDSECURIDS))) { + upgrade_secur_desc(scx->vol, + securattr, ni); + /* + * fetch owner and group for cacheing + * if there is a securid + */ + } + if (test_nino_flag(ni, v3_Extensions) + && (perm >= 0)) { + enter_cache(scx, ni, uid, + gid, pxdesc); + } + if (pxdesc) { + perm = access_check_posix(scx,pxdesc,request,uid,gid); + free(pxdesc); + } + free(securattr); + } else { + perm = -1; + uid = gid = 0; + } + } + } + return (perm); +} +#endif +/* + * Get a Posix ACL + * + * returns size or -errno if there is a problem + * if size was too small, no copy is done and errno is not set, + * the caller is expected to issue a new call + */ + +int ntfs_get_posix_acl(struct SECURITY_CONTEXT *scx, ntfs_inode *ni, + const char *name, char *value, size_t size) +{ + const SECURITY_DESCRIPTOR_RELATIVE *phead; + struct POSIX_SECURITY *pxdesc; + const struct CACHED_PERMISSIONS *cached; + char *securattr; + const SID *usid; /* owner of file/directory */ + const SID *gsid; /* group of file/directory */ + uid_t uid; + gid_t gid; + int perm; + BOOL isdir; + size_t outsize; + + outsize = 0; /* default to error */ + if (!scx->mapping[MAPUSERS]) + errno = ENOTSUP; + else { + /* check whether available in cache */ + cached = fetch_cache(scx,ni); + if (cached) + pxdesc = cached->pxdesc; + else { + securattr = getsecurityattr(scx->vol, ni); + isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) + != const_cpu_to_le16(0); + if (securattr) { + phead = + (const SECURITY_DESCRIPTOR_RELATIVE*) + securattr; + gsid = (const SID*)& + securattr[le32_to_cpu(phead->group)]; +#if OWNERFROMACL + usid = ntfs_acl_owner(securattr); +#else + usid = (const SID*)& + securattr[le32_to_cpu(phead->owner)]; +#endif + pxdesc = ntfs_build_permissions_posix(scx->mapping,securattr, + usid, gsid, isdir); + + /* + * fetch owner and group for cacheing + */ + if (pxdesc) { + perm = pxdesc->mode & 07777; + /* + * Create a security id if there were none + * and upgrade option is selected + */ + if (!test_nino_flag(ni, v3_Extensions) + && (scx->vol->secure_flags + & (1 << SECURITY_ADDSECURIDS))) { + upgrade_secur_desc(scx->vol, + securattr, ni); + } +#if OWNERFROMACL + uid = ntfs_find_user(scx->mapping[MAPUSERS],usid); +#else + if (!perm && ntfs_same_sid(usid, adminsid)) { + uid = find_tenant(scx, + securattr); + if (uid) + perm = 0700; + } else + uid = ntfs_find_user(scx->mapping[MAPUSERS],usid); +#endif + gid = ntfs_find_group(scx->mapping[MAPGROUPS],gsid); + if (pxdesc->tagsset & POSIX_ACL_EXTENSIONS) + enter_cache(scx, ni, uid, + gid, pxdesc); + } + free(securattr); + } else + pxdesc = (struct POSIX_SECURITY*)NULL; + } + + if (pxdesc) { + if (ntfs_valid_posix(pxdesc)) { + if (!strcmp(name,"system.posix_acl_default")) { + if (ni->mrec->flags + & MFT_RECORD_IS_DIRECTORY) + outsize = sizeof(struct POSIX_ACL) + + pxdesc->defcnt*sizeof(struct POSIX_ACE); + else { + /* + * getting default ACL from plain file : + * return EACCES if size > 0 as + * indicated in the man, but return ok + * if size == 0, so that ls does not + * display an error + */ + if (size > 0) { + outsize = 0; + errno = EACCES; + } else + outsize = sizeof(struct POSIX_ACL); + } + if (outsize && (outsize <= size)) { + memcpy(value,&pxdesc->acl,sizeof(struct POSIX_ACL)); + memcpy(&value[sizeof(struct POSIX_ACL)], + &pxdesc->acl.ace[pxdesc->firstdef], + outsize-sizeof(struct POSIX_ACL)); + } + } else { + outsize = sizeof(struct POSIX_ACL) + + pxdesc->acccnt*sizeof(struct POSIX_ACE); + if (outsize <= size) + memcpy(value,&pxdesc->acl,outsize); + } + } else { + outsize = 0; + errno = EIO; + ntfs_log_error("Invalid Posix ACL built\n"); + } + if (!cached) + free(pxdesc); + } else + outsize = 0; + } + return (outsize ? (int)outsize : -errno); +} + +#else /* POSIXACLS */ + + +/* + * Get permissions to access a file + * Takes into account the relation of user to file (owner, group, ...) + * Do no use as mode of the file + * + * returns -1 if there is a problem + */ +#if 0 +static int ntfs_get_perm(struct SECURITY_CONTEXT *scx, + ntfs_inode *ni, mode_t request) +{ + const SECURITY_DESCRIPTOR_RELATIVE *phead; + const struct CACHED_PERMISSIONS *cached; + char *securattr; + const SID *usid; /* owner of file/directory */ + const SID *gsid; /* group of file/directory */ + BOOL isdir; + uid_t uid; + gid_t gid; + int perm; + + if (!scx->mapping[MAPUSERS] || (!scx->uid && !(request & S_IEXEC))) + perm = 07777; + else { + /* check whether available in cache */ + cached = fetch_cache(scx,ni); + if (cached) { + perm = cached->mode; + uid = cached->uid; + gid = cached->gid; + } else { + perm = 0; /* default to no permission */ + isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) + != const_cpu_to_le16(0); + securattr = getsecurityattr(scx->vol, ni); + if (securattr) { + phead = (const SECURITY_DESCRIPTOR_RELATIVE*) + securattr; + gsid = (const SID*)& + securattr[le32_to_cpu(phead->group)]; + gid = ntfs_find_group(scx->mapping[MAPGROUPS],gsid); +#if OWNERFROMACL + usid = ntfs_acl_owner(securattr); + perm = ntfs_build_permissions(securattr, + usid, gsid, isdir); + uid = ntfs_find_user(scx->mapping[MAPUSERS],usid); +#else + usid = (const SID*)& + securattr[le32_to_cpu(phead->owner)]; + perm = ntfs_build_permissions(securattr, + usid, gsid, isdir); + if (!perm && ntfs_same_sid(usid, adminsid)) { + uid = find_tenant(scx, securattr); + if (uid) + perm = 0700; + } else + uid = ntfs_find_user(scx->mapping[MAPUSERS],usid); +#endif + /* + * Create a security id if there were none + * and upgrade option is selected + */ + if (!test_nino_flag(ni, v3_Extensions) + && (perm >= 0) + && (scx->vol->secure_flags + & (1 << SECURITY_ADDSECURIDS))) { + upgrade_secur_desc(scx->vol, + securattr, ni); + /* + * fetch owner and group for cacheing + * if there is a securid + */ + } + if (test_nino_flag(ni, v3_Extensions) + && (perm >= 0)) { + enter_cache(scx, ni, uid, + gid, perm); + } + free(securattr); + } else { + perm = -1; + uid = gid = 0; + } + } + if (perm >= 0) { + if (!scx->uid) { + /* root access and execution */ + if (perm & 0111) + perm = 07777; + else + perm = 0; + } else + if (uid == scx->uid) + perm &= 07700; + else + /* + * avoid checking group membership + * when the requested perms for group + * are the same as perms for other + */ + if ((gid == scx->gid) + || ((((perm >> 3) ^ perm) + & (request >> 6) & 7) + && groupmember(scx, scx->uid, gid))) + perm &= 07070; + else + perm &= 07007; + } + } + return (perm); +} +#endif +#endif /* POSIXACLS */ + +/* + * Get an NTFS ACL + * + * Returns size or -errno if there is a problem + * if size was too small, no copy is done and errno is not set, + * the caller is expected to issue a new call + */ + +int ntfs_get_ntfs_acl(struct SECURITY_CONTEXT *scx, ntfs_inode *ni, + char *value, size_t size) +{ + char *securattr; + size_t outsize; + + outsize = 0; /* default to no data and no error */ + securattr = getsecurityattr(scx->vol, ni); + if (securattr) { + outsize = ntfs_attr_size(securattr); + if (outsize <= size) { + memcpy(value,securattr,outsize); + } + free(securattr); + } + return (outsize ? (int)outsize : -errno); +} + +/* + * Get owner, group and permissions in an stat structure + * returns permissions, or -1 if there is a problem + */ + +int ntfs_get_owner_mode(struct SECURITY_CONTEXT *scx, + ntfs_inode * ni, struct stat *stbuf) +{ + const SECURITY_DESCRIPTOR_RELATIVE *phead; + char *securattr; + const SID *usid; /* owner of file/directory */ + const SID *gsid; /* group of file/directory */ + const struct CACHED_PERMISSIONS *cached; + int perm; + BOOL isdir; +#if POSIXACLS + struct POSIX_SECURITY *pxdesc; +#endif + + if (!scx->mapping[MAPUSERS]) + perm = 07777; + else { + /* check whether available in cache */ + cached = fetch_cache(scx,ni); + if (cached) { + perm = cached->mode; + stbuf->st_uid = cached->uid; + stbuf->st_gid = cached->gid; + stbuf->st_mode = (stbuf->st_mode & ~07777) + perm; + } else { + perm = -1; /* default to error */ + isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) + != const_cpu_to_le16(0); + securattr = getsecurityattr(scx->vol, ni); + if (securattr) { + phead = + (const SECURITY_DESCRIPTOR_RELATIVE*) + securattr; + gsid = (const SID*)& + securattr[le32_to_cpu(phead->group)]; +#if OWNERFROMACL + usid = ntfs_acl_owner(securattr); +#else + usid = (const SID*)& + securattr[le32_to_cpu(phead->owner)]; +#endif +#if POSIXACLS + pxdesc = ntfs_build_permissions_posix(scx->mapping, securattr, + usid, gsid, isdir); + if (pxdesc) + perm = pxdesc->mode & 07777; + else + perm = -1; +#else + perm = ntfs_build_permissions(securattr, + usid, gsid, isdir); +#endif + /* + * fetch owner and group for cacheing + */ + if (perm >= 0) { + /* + * Create a security id if there were none + * and upgrade option is selected + */ + if (!test_nino_flag(ni, v3_Extensions) + && (scx->vol->secure_flags + & (1 << SECURITY_ADDSECURIDS))) { + upgrade_secur_desc(scx->vol, + securattr, ni); + } +#if OWNERFROMACL + stbuf->st_uid = ntfs_find_user(scx->mapping[MAPUSERS],usid); +#else + if (!perm && ntfs_same_sid(usid, adminsid)) { + stbuf->st_uid = + find_tenant(scx, + securattr); + if (stbuf->st_uid) + perm = 0700; + } else + stbuf->st_uid = ntfs_find_user(scx->mapping[MAPUSERS],usid); +#endif + stbuf->st_gid = ntfs_find_group(scx->mapping[MAPGROUPS],gsid); + stbuf->st_mode = + (stbuf->st_mode & ~07777) + perm; +#if POSIXACLS + enter_cache(scx, ni, stbuf->st_uid, + stbuf->st_gid, pxdesc); + free(pxdesc); +#else + enter_cache(scx, ni, stbuf->st_uid, + stbuf->st_gid, perm); +#endif + } + free(securattr); + } + } + } + return (perm); +} + +#if POSIXACLS + +/* + * Get the base for a Posix inheritance and + * build an inherited Posix descriptor + */ + +static struct POSIX_SECURITY *inherit_posix(struct SECURITY_CONTEXT *scx, + ntfs_inode *dir_ni, mode_t mode, BOOL isdir) +{ + const struct CACHED_PERMISSIONS *cached; + const SECURITY_DESCRIPTOR_RELATIVE *phead; + struct POSIX_SECURITY *pxdesc; + struct POSIX_SECURITY *pydesc; + char *securattr; + const SID *usid; + const SID *gsid; + uid_t uid; + gid_t gid; + + pydesc = (struct POSIX_SECURITY*)NULL; + /* check whether parent directory is available in cache */ + cached = fetch_cache(scx,dir_ni); + if (cached) { + uid = cached->uid; + gid = cached->gid; + pxdesc = cached->pxdesc; + if (pxdesc) { + pydesc = ntfs_build_inherited_posix(pxdesc,mode, + scx->umask,isdir); + } + } else { + securattr = getsecurityattr(scx->vol, dir_ni); + if (securattr) { + phead = (const SECURITY_DESCRIPTOR_RELATIVE*) + securattr; + gsid = (const SID*)& + securattr[le32_to_cpu(phead->group)]; + gid = ntfs_find_group(scx->mapping[MAPGROUPS],gsid); +#if OWNERFROMACL + usid = ntfs_acl_owner(securattr); + pxdesc = ntfs_build_permissions_posix(scx->mapping,securattr, + usid, gsid, TRUE); + uid = ntfs_find_user(scx->mapping[MAPUSERS],usid); +#else + usid = (const SID*)& + securattr[le32_to_cpu(phead->owner)]; + pxdesc = ntfs_build_permissions_posix(scx->mapping,securattr, + usid, gsid, TRUE); + if (pxdesc && ntfs_same_sid(usid, adminsid)) { + uid = find_tenant(scx, securattr); + } else + uid = ntfs_find_user(scx->mapping[MAPUSERS],usid); +#endif + if (pxdesc) { + /* + * Create a security id if there were none + * and upgrade option is selected + */ + if (!test_nino_flag(dir_ni, v3_Extensions) + && (scx->vol->secure_flags + & (1 << SECURITY_ADDSECURIDS))) { + upgrade_secur_desc(scx->vol, + securattr, dir_ni); + /* + * fetch owner and group for cacheing + * if there is a securid + */ + } + if (test_nino_flag(dir_ni, v3_Extensions)) { + enter_cache(scx, dir_ni, uid, + gid, pxdesc); + } + pydesc = ntfs_build_inherited_posix(pxdesc, + mode, scx->umask, isdir); + free(pxdesc); + } + free(securattr); + } + } + return (pydesc); +} + +/* + * Allocate a security_id for a file being created + * + * Returns zero if not possible (NTFS v3.x required) + */ + +le32 ntfs_alloc_securid(struct SECURITY_CONTEXT *scx, + uid_t uid, gid_t gid, ntfs_inode *dir_ni, + mode_t mode, BOOL isdir) +{ +#if !FORCE_FORMAT_v1x + const struct CACHED_SECURID *cached; + struct CACHED_SECURID wanted; + struct POSIX_SECURITY *pxdesc; + char *newattr; + int newattrsz; + const SID *usid; + const SID *gsid; + BIGSID defusid; + BIGSID defgsid; + le32 securid; +#endif + + securid = const_cpu_to_le32(0); + +#if !FORCE_FORMAT_v1x + + pxdesc = inherit_posix(scx, dir_ni, mode, isdir); + if (pxdesc) { + /* check whether target securid is known in cache */ + + wanted.uid = uid; + wanted.gid = gid; + wanted.dmode = pxdesc->mode & mode & 07777; + if (isdir) wanted.dmode |= 0x10000; + wanted.variable = (void*)pxdesc; + wanted.varsize = sizeof(struct POSIX_SECURITY) + + (pxdesc->acccnt + pxdesc->defcnt)*sizeof(struct POSIX_ACE); + cached = (const struct CACHED_SECURID*)ntfs_fetch_cache( + scx->vol->securid_cache, GENERIC(&wanted), + (cache_compare)compare); + /* quite simple, if we are lucky */ + if (cached) + securid = cached->securid; + + /* not in cache : make sure we can create ids */ + + if (!cached && (scx->vol->major_ver >= 3)) { + usid = ntfs_find_usid(scx->mapping[MAPUSERS],uid,(SID*)&defusid); + gsid = ntfs_find_gsid(scx->mapping[MAPGROUPS],gid,(SID*)&defgsid); + if (!usid || !gsid) { + ntfs_log_error("File created by an unmapped user/group %d/%d\n", + (int)uid, (int)gid); + usid = gsid = adminsid; + } + newattr = ntfs_build_descr_posix(scx->mapping, pxdesc, + isdir, usid, gsid); + if (newattr) { + newattrsz = ntfs_attr_size(newattr); + securid = setsecurityattr(scx->vol, + (const SECURITY_DESCRIPTOR_RELATIVE*)newattr, + newattrsz); + if (securid) { + /* update cache, for subsequent use */ + wanted.securid = securid; + ntfs_enter_cache(scx->vol->securid_cache, + GENERIC(&wanted), + (cache_compare)compare); + } + free(newattr); + } else { + /* + * could not build new security attribute + * errno set by ntfs_build_descr() + */ + } + } + free(pxdesc); + } +#endif + return (securid); +} + +/* + * Apply Posix inheritance to a newly created file + * (for NTFS 1.x only : no securid) + */ + +int ntfs_set_inherited_posix(struct SECURITY_CONTEXT *scx, + ntfs_inode *ni, uid_t uid, gid_t gid, + ntfs_inode *dir_ni, mode_t mode) +{ + struct POSIX_SECURITY *pxdesc; + char *newattr; + const SID *usid; + const SID *gsid; + BIGSID defusid; + BIGSID defgsid; + BOOL isdir; + int res; + + res = -1; + isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) != const_cpu_to_le16(0); + pxdesc = inherit_posix(scx, dir_ni, mode, isdir); + if (pxdesc) { + usid = ntfs_find_usid(scx->mapping[MAPUSERS],uid,(SID*)&defusid); + gsid = ntfs_find_gsid(scx->mapping[MAPGROUPS],gid,(SID*)&defgsid); + if (!usid || !gsid) { + ntfs_log_error("File created by an unmapped user/group %d/%d\n", + (int)uid, (int)gid); + usid = gsid = adminsid; + } + newattr = ntfs_build_descr_posix(scx->mapping, pxdesc, + isdir, usid, gsid); + if (newattr) { + /* Adjust Windows read-only flag */ + res = update_secur_descr(scx->vol, newattr, ni); + if (!res && !isdir) { + if (mode & S_IWUSR) + ni->flags &= ~FILE_ATTR_READONLY; + else + ni->flags |= FILE_ATTR_READONLY; + } +#if CACHE_LEGACY_SIZE + /* also invalidate legacy cache */ + if (isdir && !ni->security_id) { + struct CACHED_PERMISSIONS_LEGACY legacy; + + legacy.mft_no = ni->mft_no; + legacy.variable = pxdesc; + legacy.varsize = sizeof(struct POSIX_SECURITY) + + (pxdesc->acccnt + pxdesc->defcnt)*sizeof(struct POSIX_ACE); + ntfs_invalidate_cache(scx->vol->legacy_cache, + GENERIC(&legacy), + (cache_compare)leg_compare,0); + } +#endif + free(newattr); + + } else { + /* + * could not build new security attribute + * errno set by ntfs_build_descr() + */ + } + } + return (res); +} + +#else + +le32 ntfs_alloc_securid(struct SECURITY_CONTEXT *scx, + uid_t uid, gid_t gid, mode_t mode, BOOL isdir) +{ +#if !FORCE_FORMAT_v1x + const struct CACHED_SECURID *cached; + struct CACHED_SECURID wanted; + char *newattr; + int newattrsz; + const SID *usid; + const SID *gsid; + BIGSID defusid; + BIGSID defgsid; + le32 securid; +#endif + + securid = const_cpu_to_le32(0); + +#if !FORCE_FORMAT_v1x + /* check whether target securid is known in cache */ + + wanted.uid = uid; + wanted.gid = gid; + wanted.dmode = mode & 07777; + if (isdir) wanted.dmode |= 0x10000; + wanted.variable = (void*)NULL; + wanted.varsize = 0; + cached = (const struct CACHED_SECURID*)ntfs_fetch_cache( + scx->vol->securid_cache, GENERIC(&wanted), + (cache_compare)compare); + /* quite simple, if we are lucky */ + if (cached) + securid = cached->securid; + + /* not in cache : make sure we can create ids */ + + if (!cached && (scx->vol->major_ver >= 3)) { + usid = ntfs_find_usid(scx->mapping[MAPUSERS],uid,(SID*)&defusid); + gsid = ntfs_find_gsid(scx->mapping[MAPGROUPS],gid,(SID*)&defgsid); + if (!usid || !gsid) { + ntfs_log_error("File created by an unmapped user/group %d/%d\n", + (int)uid, (int)gid); + usid = gsid = adminsid; + } + newattr = ntfs_build_descr(mode, isdir, usid, gsid); + if (newattr) { + newattrsz = ntfs_attr_size(newattr); + securid = setsecurityattr(scx->vol, + (const SECURITY_DESCRIPTOR_RELATIVE*)newattr, + newattrsz); + if (securid) { + /* update cache, for subsequent use */ + wanted.securid = securid; + ntfs_enter_cache(scx->vol->securid_cache, + GENERIC(&wanted), + (cache_compare)compare); + } + free(newattr); + } else { + /* + * could not build new security attribute + * errno set by ntfs_build_descr() + */ + } + } +#endif + return (securid); +} + +#endif + +/* + * Update ownership and mode of a file, reusing an existing + * security descriptor when possible + * + * Returns zero if successful + */ + +#if POSIXACLS +int ntfs_set_owner_mode(struct SECURITY_CONTEXT *scx, ntfs_inode *ni, + uid_t uid, gid_t gid, mode_t mode, + struct POSIX_SECURITY *pxdesc) +#else +int ntfs_set_owner_mode(struct SECURITY_CONTEXT *scx, ntfs_inode *ni, + uid_t uid, gid_t gid, mode_t mode) +#endif +{ + int res; + const struct CACHED_SECURID *cached; + struct CACHED_SECURID wanted; + char *newattr; + const SID *usid; + const SID *gsid; + BIGSID defusid; + BIGSID defgsid; + BOOL isdir; + + res = 0; + + /* check whether target securid is known in cache */ + + isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) != const_cpu_to_le16(0); + wanted.uid = uid; + wanted.gid = gid; + wanted.dmode = mode & 07777; + if (isdir) wanted.dmode |= 0x10000; +#if POSIXACLS + wanted.variable = (void*)pxdesc; + if (pxdesc) + wanted.varsize = sizeof(struct POSIX_SECURITY) + + (pxdesc->acccnt + pxdesc->defcnt)*sizeof(struct POSIX_ACE); + else + wanted.varsize = 0; +#else + wanted.variable = (void*)NULL; + wanted.varsize = 0; +#endif + if (test_nino_flag(ni, v3_Extensions)) { + cached = (const struct CACHED_SECURID*)ntfs_fetch_cache( + scx->vol->securid_cache, GENERIC(&wanted), + (cache_compare)compare); + /* quite simple, if we are lucky */ + if (cached) { + ni->security_id = cached->securid; + NInoSetDirty(ni); + } + } else cached = (struct CACHED_SECURID*)NULL; + + if (!cached) { + /* + * Do not use usid and gsid from former attributes, + * but recompute them to get repeatable results + * which can be kept in cache. + */ + usid = ntfs_find_usid(scx->mapping[MAPUSERS],uid,(SID*)&defusid); + gsid = ntfs_find_gsid(scx->mapping[MAPGROUPS],gid,(SID*)&defgsid); + if (!usid || !gsid) { + ntfs_log_error("File made owned by an unmapped user/group %d/%d\n", + uid, gid); + usid = gsid = adminsid; + } +#if POSIXACLS + if (pxdesc) + newattr = ntfs_build_descr_posix(scx->mapping, pxdesc, + isdir, usid, gsid); + else + newattr = ntfs_build_descr(mode, + isdir, usid, gsid); +#else + newattr = ntfs_build_descr(mode, + isdir, usid, gsid); +#endif + if (newattr) { + res = update_secur_descr(scx->vol, newattr, ni); + if (!res) { + /* adjust Windows read-only flag */ + if (!isdir) { + if (mode & S_IWUSR) + ni->flags &= ~FILE_ATTR_READONLY; + else + ni->flags |= FILE_ATTR_READONLY; + NInoFileNameSetDirty(ni); + } + /* update cache, for subsequent use */ + if (test_nino_flag(ni, v3_Extensions)) { + wanted.securid = ni->security_id; + ntfs_enter_cache(scx->vol->securid_cache, + GENERIC(&wanted), + (cache_compare)compare); + } +#if CACHE_LEGACY_SIZE + /* also invalidate legacy cache */ + if (isdir && !ni->security_id) { + struct CACHED_PERMISSIONS_LEGACY legacy; + + legacy.mft_no = ni->mft_no; +#if POSIXACLS + legacy.variable = wanted.variable; + legacy.varsize = wanted.varsize; +#else + legacy.variable = (void*)NULL; + legacy.varsize = 0; +#endif + ntfs_invalidate_cache(scx->vol->legacy_cache, + GENERIC(&legacy), + (cache_compare)leg_compare,0); + } +#endif + } + free(newattr); + } else { + /* + * could not build new security attribute + * errno set by ntfs_build_descr() + */ + res = -1; + } + } + return (res); +} + +/* + * Check whether user has ownership rights on a file + * + * Returns TRUE if allowed + * if not, errno tells why + */ + +BOOL ntfs_allowed_as_owner(struct SECURITY_CONTEXT *scx, ntfs_inode *ni) +{ + const struct CACHED_PERMISSIONS *cached; + char *oldattr; + const SID *usid; + uid_t processuid; + uid_t uid; + BOOL gotowner; + int allowed; + + processuid = scx->uid; +/* TODO : use CAP_FOWNER process capability */ + /* + * Always allow for root + * Also always allow if no mapping has been defined + */ + if (!scx->mapping[MAPUSERS] || !processuid) + allowed = TRUE; + else { + gotowner = FALSE; /* default */ + /* get the owner, either from cache or from old attribute */ + cached = fetch_cache(scx, ni); + if (cached) { + uid = cached->uid; + gotowner = TRUE; + } else { + oldattr = getsecurityattr(scx->vol, ni); + if (oldattr) { +#if OWNERFROMACL + usid = ntfs_acl_owner(oldattr); +#else + const SECURITY_DESCRIPTOR_RELATIVE *phead; + + phead = (const SECURITY_DESCRIPTOR_RELATIVE*) + oldattr; + usid = (const SID*)&oldattr + [le32_to_cpu(phead->owner)]; +#endif + uid = ntfs_find_user(scx->mapping[MAPUSERS], + usid); + gotowner = TRUE; + free(oldattr); + } + } + allowed = FALSE; + if (gotowner) { +/* TODO : use CAP_FOWNER process capability */ + if (!processuid || (processuid == uid)) + allowed = TRUE; + else + errno = EPERM; + } + } + return (allowed); +} + +#ifdef HAVE_SETXATTR /* extended attributes interface required */ + +#if POSIXACLS + +/* + * Set a new access or default Posix ACL to a file + * (or remove ACL if no input data) + * Validity of input data is checked after merging + * + * Returns 0, or -1 if there is a problem which errno describes + */ + +int ntfs_set_posix_acl(struct SECURITY_CONTEXT *scx, ntfs_inode *ni, + const char *name, const char *value, size_t size, + int flags) +{ + const SECURITY_DESCRIPTOR_RELATIVE *phead; + const struct CACHED_PERMISSIONS *cached; + char *oldattr; + uid_t processuid; + const SID *usid; + const SID *gsid; + uid_t uid; + uid_t gid; + int res; + mode_t mode; + BOOL isdir; + BOOL deflt; + BOOL exist; + int count; + struct POSIX_SECURITY *oldpxdesc; + struct POSIX_SECURITY *newpxdesc; + + /* get the current pxsec, either from cache or from old attribute */ + res = -1; + deflt = !strcmp(name,"system.posix_acl_default"); + if (size) + count = (size - sizeof(struct POSIX_ACL)) / sizeof(struct POSIX_ACE); + else + count = 0; + isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) != const_cpu_to_le16(0); + newpxdesc = (struct POSIX_SECURITY*)NULL; + if (!deflt || isdir || !size) { + cached = fetch_cache(scx, ni); + if (cached) { + uid = cached->uid; + gid = cached->gid; + oldpxdesc = cached->pxdesc; + if (oldpxdesc) { + mode = oldpxdesc->mode; + newpxdesc = ntfs_replace_acl(oldpxdesc, + (const struct POSIX_ACL*)value,count,deflt); + } + } else { + oldattr = getsecurityattr(scx->vol, ni); + if (oldattr) { + phead = (const SECURITY_DESCRIPTOR_RELATIVE*)oldattr; +#if OWNERFROMACL + usid = ntfs_acl_owner(oldattr); +#else + usid = (const SID*)&oldattr[le32_to_cpu(phead->owner)]; +#endif + gsid = (const SID*)&oldattr[le32_to_cpu(phead->group)]; + uid = ntfs_find_user(scx->mapping[MAPUSERS],usid); + gid = ntfs_find_group(scx->mapping[MAPGROUPS],gsid); + oldpxdesc = ntfs_build_permissions_posix(scx->mapping, + oldattr, usid, gsid, isdir); + if (oldpxdesc) { + if (deflt) + exist = oldpxdesc->defcnt > 0; + else + exist = oldpxdesc->acccnt > 3; + if ((exist && (flags & XATTR_CREATE)) + || (!exist && (flags & XATTR_REPLACE))) { + errno = (exist ? EEXIST : ENODATA); + } else { + mode = oldpxdesc->mode; + newpxdesc = ntfs_replace_acl(oldpxdesc, + (const struct POSIX_ACL*)value,count,deflt); + } + free(oldpxdesc); + } + free(oldattr); + } + } + } else + errno = EINVAL; + + if (newpxdesc) { + processuid = scx->uid; +/* TODO : use CAP_FOWNER process capability */ + if (!processuid || (uid == processuid)) { + /* + * clear setgid if file group does + * not match process group + */ + if (processuid && (gid != scx->gid) + && !groupmember(scx, scx->uid, gid)) { + newpxdesc->mode &= ~S_ISGID; + } + res = ntfs_set_owner_mode(scx, ni, uid, gid, + newpxdesc->mode, newpxdesc); + } else + errno = EPERM; + free(newpxdesc); + } + return (res ? -1 : 0); +} + +/* + * Remove a default Posix ACL from a file + * + * Returns 0, or -1 if there is a problem which errno describes + */ + +int ntfs_remove_posix_acl(struct SECURITY_CONTEXT *scx, ntfs_inode *ni, + const char *name) +{ + return (ntfs_set_posix_acl(scx, ni, name, + (const char*)NULL, 0, 0)); +} + +#endif + +/* + * Set a new NTFS ACL to a file + * + * Returns 0, or -1 if there is a problem + */ + +int ntfs_set_ntfs_acl(struct SECURITY_CONTEXT *scx, ntfs_inode *ni, + const char *value, size_t size, int flags) +{ + char *attr; + int res; + + res = -1; + if ((size > 0) + && !(flags & XATTR_CREATE) + && ntfs_valid_descr(value,size) + && (ntfs_attr_size(value) == size)) { + /* need copying in order to write */ + attr = (char*)ntfs_malloc(size); + if (attr) { + memcpy(attr,value,size); + res = update_secur_descr(scx->vol, attr, ni); + /* + * No need to invalidate standard caches : + * the relation between a securid and + * the associated protection is unchanged, + * only the relation between a file and + * its securid and protection is changed. + */ +#if CACHE_LEGACY_SIZE + /* + * we must however invalidate the legacy + * cache, which is based on inode numbers. + * For safety, invalidate even if updating + * failed. + */ + if ((ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) + && !ni->security_id) { + struct CACHED_PERMISSIONS_LEGACY legacy; + + legacy.mft_no = ni->mft_no; + legacy.variable = (char*)NULL; + legacy.varsize = 0; + ntfs_invalidate_cache(scx->vol->legacy_cache, + GENERIC(&legacy), + (cache_compare)leg_compare,0); + } +#endif + free(attr); + } else + errno = ENOMEM; + } else + errno = EINVAL; + return (res ? -1 : 0); +} + +#endif /* HAVE_SETXATTR */ + +/* + * Set new permissions to a file + * Checks user mapping has been defined before request for setting + * + * rejected if request is not originated by owner or root + * + * returns 0 on success + * -1 on failure, with errno = EIO + */ + +int ntfs_set_mode(struct SECURITY_CONTEXT *scx, ntfs_inode *ni, mode_t mode) +{ + const SECURITY_DESCRIPTOR_RELATIVE *phead; + const struct CACHED_PERMISSIONS *cached; + char *oldattr; + const SID *usid; + const SID *gsid; + uid_t processuid; + uid_t uid; + uid_t gid; + int res; +#if POSIXACLS + BOOL isdir; + int pxsize; + const struct POSIX_SECURITY *oldpxdesc; + struct POSIX_SECURITY *newpxdesc = (struct POSIX_SECURITY*)NULL; +#endif + + /* get the current owner, either from cache or from old attribute */ + res = 0; + cached = fetch_cache(scx, ni); + if (cached) { + uid = cached->uid; + gid = cached->gid; +#if POSIXACLS + oldpxdesc = cached->pxdesc; + if (oldpxdesc) { + /* must copy before merging */ + pxsize = sizeof(struct POSIX_SECURITY) + + (oldpxdesc->acccnt + oldpxdesc->defcnt)*sizeof(struct POSIX_ACE); + newpxdesc = (struct POSIX_SECURITY*)malloc(pxsize); + if (newpxdesc) { + memcpy(newpxdesc, oldpxdesc, pxsize); + if (ntfs_merge_mode_posix(newpxdesc, mode)) + res = -1; + } else + res = -1; + } else + newpxdesc = (struct POSIX_SECURITY*)NULL; +#endif + } else { + oldattr = getsecurityattr(scx->vol, ni); + if (oldattr) { + phead = (const SECURITY_DESCRIPTOR_RELATIVE*)oldattr; +#if OWNERFROMACL + usid = ntfs_acl_owner(oldattr); +#else + usid = (const SID*)&oldattr[le32_to_cpu(phead->owner)]; +#endif + gsid = (const SID*)&oldattr[le32_to_cpu(phead->group)]; + uid = ntfs_find_user(scx->mapping[MAPUSERS],usid); + gid = ntfs_find_group(scx->mapping[MAPGROUPS],gsid); +#if POSIXACLS + isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) != const_cpu_to_le16(0); + newpxdesc = ntfs_build_permissions_posix(scx->mapping, + oldattr, usid, gsid, isdir); + if (!newpxdesc || ntfs_merge_mode_posix(newpxdesc, mode)) + res = -1; +#endif + free(oldattr); + } else + res = -1; + } + + if (!res) { + processuid = scx->uid; +/* TODO : use CAP_FOWNER process capability */ + if (!processuid || (uid == processuid)) { + /* + * clear setgid if file group does + * not match process group + */ + if (processuid && (gid != scx->gid) + && !groupmember(scx, scx->uid, gid)) + mode &= ~S_ISGID; +#if POSIXACLS + if (newpxdesc) { + newpxdesc->mode = mode; + res = ntfs_set_owner_mode(scx, ni, uid, gid, + mode, newpxdesc); + } else + res = ntfs_set_owner_mode(scx, ni, uid, gid, + mode, newpxdesc); +#else + res = ntfs_set_owner_mode(scx, ni, uid, gid, mode); +#endif + } else { + errno = EPERM; + res = -1; /* neither owner nor root */ + } + } else { + /* + * Should not happen : a default descriptor is generated + * by getsecurityattr() when there are none + */ + ntfs_log_error("File has no security descriptor\n"); + res = -1; + errno = EIO; + } +#if POSIXACLS + if (newpxdesc) free(newpxdesc); +#endif + return (res ? -1 : 0); +} + +/* + * Create a default security descriptor for files whose descriptor + * cannot be inherited + */ + +int ntfs_sd_add_everyone(ntfs_inode *ni) +{ + /* JPA SECURITY_DESCRIPTOR_ATTR *sd; */ + SECURITY_DESCRIPTOR_RELATIVE *sd; + ACL *acl; + ACCESS_ALLOWED_ACE *ace; + SID *sid; + int ret, sd_len; + + /* Create SECURITY_DESCRIPTOR attribute (everyone has full access). */ + /* + * Calculate security descriptor length. We have 2 sub-authorities in + * owner and group SIDs, but structure SID contain only one, so add + * 4 bytes to every SID. + */ + sd_len = sizeof(SECURITY_DESCRIPTOR_ATTR) + 2 * (sizeof(SID) + 4) + + sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE); + sd = (SECURITY_DESCRIPTOR_RELATIVE*)ntfs_calloc(sd_len); + if (!sd) + return -1; + + sd->revision = SECURITY_DESCRIPTOR_REVISION; + sd->control = SE_DACL_PRESENT | SE_SELF_RELATIVE; + + sid = (SID*)((u8*)sd + sizeof(SECURITY_DESCRIPTOR_ATTR)); + sid->revision = SID_REVISION; + sid->sub_authority_count = 2; + sid->sub_authority[0] = const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID); + sid->sub_authority[1] = const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS); + sid->identifier_authority.value[5] = 5; + sd->owner = cpu_to_le32((u8*)sid - (u8*)sd); + + sid = (SID*)((u8*)sid + sizeof(SID) + 4); + sid->revision = SID_REVISION; + sid->sub_authority_count = 2; + sid->sub_authority[0] = const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID); + sid->sub_authority[1] = const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS); + sid->identifier_authority.value[5] = 5; + sd->group = cpu_to_le32((u8*)sid - (u8*)sd); + + acl = (ACL*)((u8*)sid + sizeof(SID) + 4); + acl->revision = ACL_REVISION; + acl->size = const_cpu_to_le16(sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE)); + acl->ace_count = const_cpu_to_le16(1); + sd->dacl = cpu_to_le32((u8*)acl - (u8*)sd); + + ace = (ACCESS_ALLOWED_ACE*)((u8*)acl + sizeof(ACL)); + ace->type = ACCESS_ALLOWED_ACE_TYPE; + ace->flags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE; + ace->size = const_cpu_to_le16(sizeof(ACCESS_ALLOWED_ACE)); + ace->mask = const_cpu_to_le32(0x1f01ff); /* FIXME */ + ace->sid.revision = SID_REVISION; + ace->sid.sub_authority_count = 1; + ace->sid.sub_authority[0] = const_cpu_to_le32(0); + ace->sid.identifier_authority.value[5] = 1; + + ret = ntfs_attr_add(ni, AT_SECURITY_DESCRIPTOR, AT_UNNAMED, 0, (u8*)sd, + sd_len); + if (ret) + ntfs_log_perror("Failed to add initial SECURITY_DESCRIPTOR"); + + free(sd); + return ret; +} + +/* + * Check whether user can access a file in a specific way + * + * Returns 1 if access is allowed, including user is root or no + * user mapping defined + * 2 if sticky and accesstype is S_IWRITE + S_IEXEC + S_ISVTX + * 0 and sets errno if there is a problem or if access + * is not allowed + * + * This is used for Posix ACL and checking creation of DOS file names + */ + +int ntfs_allowed_access(struct SECURITY_CONTEXT *scx, + ntfs_inode *ni, + int accesstype) /* access type required (S_Ixxx values) */ +{ + return 1; + +#if 0 + int perm; + int res; + int allow; + struct stat stbuf; + + /* + * Always allow for root unless execution is requested. + * (was checked by fuse until kernel 2.6.29) + * Also always allow if no mapping has been defined + */ + if (!scx->mapping[MAPUSERS] + || (!scx->uid + && (!(accesstype & S_IEXEC) + || (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)))) + allow = 1; + else { + perm = ntfs_get_perm(scx, ni, accesstype); + if (perm >= 0) { + res = EACCES; + switch (accesstype) { + case S_IEXEC: + allow = (perm & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0; + break; + case S_IWRITE: + allow = (perm & (S_IWUSR | S_IWGRP | S_IWOTH)) != 0; + break; + case S_IWRITE + S_IEXEC: + allow = ((perm & (S_IWUSR | S_IWGRP | S_IWOTH)) != 0) + && ((perm & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0); + break; + case S_IREAD: + allow = (perm & (S_IRUSR | S_IRGRP | S_IROTH)) != 0; + break; + case S_IREAD + S_IEXEC: + allow = ((perm & (S_IRUSR | S_IRGRP | S_IROTH)) != 0) + && ((perm & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0); + break; + case S_IREAD + S_IWRITE: + allow = ((perm & (S_IRUSR | S_IRGRP | S_IROTH)) != 0) + && ((perm & (S_IWUSR | S_IWGRP | S_IWOTH)) != 0); + break; + case S_IWRITE + S_IEXEC + S_ISVTX: + if (perm & S_ISVTX) { + if ((ntfs_get_owner_mode(scx,ni,&stbuf) >= 0) + && (stbuf.st_uid == scx->uid)) + allow = 1; + else + allow = 2; + } else + allow = ((perm & (S_IWUSR | S_IWGRP | S_IWOTH)) != 0) + && ((perm & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0); + break; + case S_IREAD + S_IWRITE + S_IEXEC: + allow = ((perm & (S_IRUSR | S_IRGRP | S_IROTH)) != 0) + && ((perm & (S_IWUSR | S_IWGRP | S_IWOTH)) != 0) + && ((perm & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0); + break; + default : + res = EINVAL; + allow = 0; + break; + } + if (!allow) + errno = res; + } else + allow = 0; + } + return (allow); +#endif +} + +#if 0 /* not needed any more */ + +/* + * Check whether user can access the parent directory + * of a file in a specific way + * + * Returns true if access is allowed, including user is root and + * no user mapping defined + * + * Sets errno if there is a problem or if not allowed + * + * This is used for Posix ACL and checking creation of DOS file names + */ + +BOOL old_ntfs_allowed_dir_access(struct SECURITY_CONTEXT *scx, + const char *path, int accesstype) +{ + int allow; + char *dirpath; + char *name; + ntfs_inode *ni; + ntfs_inode *dir_ni; + struct stat stbuf; + + allow = 0; + dirpath = strdup(path); + if (dirpath) { + /* the root of file system is seen as a parent of itself */ + /* is that correct ? */ + name = strrchr(dirpath, '/'); + *name = 0; + dir_ni = ntfs_pathname_to_inode(scx->vol, NULL, dirpath); + if (dir_ni) { + allow = ntfs_allowed_access(scx, + dir_ni, accesstype); + ntfs_inode_close(dir_ni); + /* + * for an not-owned sticky directory, have to + * check whether file itself is owned + */ + if ((accesstype == (S_IWRITE + S_IEXEC + S_ISVTX)) + && (allow == 2)) { + ni = ntfs_pathname_to_inode(scx->vol, NULL, + path); + allow = FALSE; + if (ni) { + allow = (ntfs_get_owner_mode(scx,ni,&stbuf) >= 0) + && (stbuf.st_uid == scx->uid); + ntfs_inode_close(ni); + } + } + } + free(dirpath); + } + return (allow); /* errno is set if not allowed */ +} + +#endif + +/* + * Define a new owner/group to a file + * + * returns zero if successful + */ + +int ntfs_set_owner(struct SECURITY_CONTEXT *scx, ntfs_inode *ni, + uid_t uid, gid_t gid) +{ + const SECURITY_DESCRIPTOR_RELATIVE *phead; + const struct CACHED_PERMISSIONS *cached; + char *oldattr; + const SID *usid; + const SID *gsid; + uid_t fileuid; + uid_t filegid; + mode_t mode; + int perm; + BOOL isdir; + int res; +#if POSIXACLS + struct POSIX_SECURITY *pxdesc; + BOOL pxdescbuilt = FALSE; +#endif + + res = 0; + /* get the current owner and mode from cache or security attributes */ + oldattr = (char*)NULL; + cached = fetch_cache(scx,ni); + if (cached) { + fileuid = cached->uid; + filegid = cached->gid; + mode = cached->mode; +#if POSIXACLS + pxdesc = cached->pxdesc; + if (!pxdesc) + res = -1; +#endif + } else { + fileuid = 0; + filegid = 0; + mode = 0; + oldattr = getsecurityattr(scx->vol, ni); + if (oldattr) { + isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) + != const_cpu_to_le16(0); + phead = (const SECURITY_DESCRIPTOR_RELATIVE*) + oldattr; + gsid = (const SID*) + &oldattr[le32_to_cpu(phead->group)]; +#if OWNERFROMACL + usid = ntfs_acl_owner(oldattr); +#else + usid = (const SID*) + &oldattr[le32_to_cpu(phead->owner)]; +#endif +#if POSIXACLS + pxdesc = ntfs_build_permissions_posix(scx->mapping, oldattr, + usid, gsid, isdir); + if (pxdesc) { + pxdescbuilt = TRUE; + fileuid = ntfs_find_user(scx->mapping[MAPUSERS],usid); + filegid = ntfs_find_group(scx->mapping[MAPGROUPS],gsid); + mode = perm = pxdesc->mode; + } else + res = -1; +#else + mode = perm = ntfs_build_permissions(oldattr, + usid, gsid, isdir); + if (perm >= 0) { + fileuid = ntfs_find_user(scx->mapping[MAPUSERS],usid); + filegid = ntfs_find_group(scx->mapping[MAPGROUPS],gsid); + } else + res = -1; +#endif + free(oldattr); + } else + res = -1; + } + if (!res) { + /* check requested by root */ + /* or chgrp requested by owner to an owned group */ + if (!scx->uid + || ((((int)uid < 0) || (uid == fileuid)) + && ((gid == scx->gid) || groupmember(scx, scx->uid, gid)) + && (fileuid == scx->uid))) { + /* replace by the new usid and gsid */ + /* or reuse old gid and sid for cacheing */ + if ((int)uid < 0) + uid = fileuid; + if ((int)gid < 0) + gid = filegid; + /* clear setuid and setgid if owner has changed */ + /* unless request originated by root */ + if (uid && (fileuid != uid)) + mode &= 01777; +#if POSIXACLS + res = ntfs_set_owner_mode(scx, ni, uid, gid, + mode, pxdesc); +#else + res = ntfs_set_owner_mode(scx, ni, uid, gid, mode); +#endif + } else { + res = -1; /* neither owner nor root */ + errno = EPERM; + } +#if POSIXACLS + if (pxdescbuilt) + free(pxdesc); +#endif + } else { + /* + * Should not happen : a default descriptor is generated + * by getsecurityattr() when there are none + */ + ntfs_log_error("File has no security descriptor\n"); + res = -1; + errno = EIO; + } + return (res ? -1 : 0); +} + +/* + * Define new owner/group and mode to a file + * + * returns zero if successful + */ + +int ntfs_set_ownmod(struct SECURITY_CONTEXT *scx, ntfs_inode *ni, + uid_t uid, gid_t gid, const mode_t mode) +{ + const SECURITY_DESCRIPTOR_RELATIVE *phead; + const struct CACHED_PERMISSIONS *cached; + char *oldattr; + const SID *usid; + const SID *gsid; + uid_t fileuid; + uid_t filegid; + BOOL isdir; + int res; +#if POSIXACLS + const struct POSIX_SECURITY *oldpxdesc; + struct POSIX_SECURITY *newpxdesc = (struct POSIX_SECURITY*)NULL; + int pxsize; +#endif + + res = 0; + /* get the current owner and mode from cache or security attributes */ + oldattr = (char*)NULL; + cached = fetch_cache(scx,ni); + if (cached) { + fileuid = cached->uid; + filegid = cached->gid; +#if POSIXACLS + oldpxdesc = cached->pxdesc; + if (oldpxdesc) { + /* must copy before merging */ + pxsize = sizeof(struct POSIX_SECURITY) + + (oldpxdesc->acccnt + oldpxdesc->defcnt)*sizeof(struct POSIX_ACE); + newpxdesc = (struct POSIX_SECURITY*)malloc(pxsize); + if (newpxdesc) { + memcpy(newpxdesc, oldpxdesc, pxsize); + if (ntfs_merge_mode_posix(newpxdesc, mode)) + res = -1; + } else + res = -1; + } +#endif + } else { + fileuid = 0; + filegid = 0; + oldattr = getsecurityattr(scx->vol, ni); + if (oldattr) { + isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) + != const_cpu_to_le16(0); + phead = (const SECURITY_DESCRIPTOR_RELATIVE*) + oldattr; + gsid = (const SID*) + &oldattr[le32_to_cpu(phead->group)]; +#if OWNERFROMACL + usid = ntfs_acl_owner(oldattr); +#else + usid = (const SID*) + &oldattr[le32_to_cpu(phead->owner)]; +#endif +#if POSIXACLS + newpxdesc = ntfs_build_permissions_posix(scx->mapping, oldattr, + usid, gsid, isdir); + if (!newpxdesc || ntfs_merge_mode_posix(newpxdesc, mode)) + res = -1; + else { + fileuid = ntfs_find_user(scx->mapping[MAPUSERS],usid); + filegid = ntfs_find_group(scx->mapping[MAPGROUPS],gsid); + } +#endif + free(oldattr); + } else + res = -1; + } + if (!res) { + /* check requested by root */ + /* or chgrp requested by owner to an owned group */ + if (!scx->uid + || ((((int)uid < 0) || (uid == fileuid)) + && ((gid == scx->gid) || groupmember(scx, scx->uid, gid)) + && (fileuid == scx->uid))) { + /* replace by the new usid and gsid */ + /* or reuse old gid and sid for cacheing */ + if ((int)uid < 0) + uid = fileuid; + if ((int)gid < 0) + gid = filegid; +#if POSIXACLS + res = ntfs_set_owner_mode(scx, ni, uid, gid, + mode, newpxdesc); +#else + res = ntfs_set_owner_mode(scx, ni, uid, gid, mode); +#endif + } else { + res = -1; /* neither owner nor root */ + errno = EPERM; + } + } else { + /* + * Should not happen : a default descriptor is generated + * by getsecurityattr() when there are none + */ + ntfs_log_error("File has no security descriptor\n"); + res = -1; + errno = EIO; + } +#if POSIXACLS + free(newpxdesc); +#endif + return (res ? -1 : 0); +} + +/* + * Build a security id for a descriptor inherited from + * parent directory the Windows way + */ + +static le32 build_inherited_id(struct SECURITY_CONTEXT *scx, + const char *parentattr, BOOL fordir) +{ + const SECURITY_DESCRIPTOR_RELATIVE *pphead; + const ACL *ppacl; + const SID *usid; + const SID *gsid; + BIGSID defusid; + BIGSID defgsid; + int offpacl; + int offowner; + int offgroup; + SECURITY_DESCRIPTOR_RELATIVE *pnhead; + ACL *pnacl; + int parentattrsz; + char *newattr; + int newattrsz; + int aclsz; + int usidsz; + int gsidsz; + int pos; + le32 securid; + + parentattrsz = ntfs_attr_size(parentattr); + pphead = (const SECURITY_DESCRIPTOR_RELATIVE*)parentattr; + if (scx->mapping[MAPUSERS]) { + usid = ntfs_find_usid(scx->mapping[MAPUSERS], scx->uid, (SID*)&defusid); + gsid = ntfs_find_gsid(scx->mapping[MAPGROUPS], scx->gid, (SID*)&defgsid); + if (!usid) + usid = adminsid; + if (!gsid) + gsid = adminsid; + } else { + /* + * If there is no user mapping, we have to copy owner + * and group from parent directory. + * Windows never has to do that, because it can always + * rely on a user mapping + */ + offowner = le32_to_cpu(pphead->owner); + usid = (const SID*)&parentattr[offowner]; + offgroup = le32_to_cpu(pphead->group); + gsid = (const SID*)&parentattr[offgroup]; + } + /* + * new attribute is smaller than parent's + * except for differences in SIDs which appear in + * owner, group and possible grants and denials in + * generic creator-owner and creator-group ACEs. + * For directories, an ACE may be duplicated for + * access and inheritance, so we double the count. + */ + usidsz = ntfs_sid_size(usid); + gsidsz = ntfs_sid_size(gsid); + newattrsz = parentattrsz + 3*usidsz + 3*gsidsz; + if (fordir) + newattrsz *= 2; + newattr = (char*)ntfs_malloc(newattrsz); + if (newattr) { + pnhead = (SECURITY_DESCRIPTOR_RELATIVE*)newattr; + pnhead->revision = SECURITY_DESCRIPTOR_REVISION; + pnhead->alignment = 0; + pnhead->control = SE_SELF_RELATIVE; + pos = sizeof(SECURITY_DESCRIPTOR_RELATIVE); + /* + * locate and inherit DACL + * do not test SE_DACL_PRESENT (wrong for "DR Watson") + */ + pnhead->dacl = const_cpu_to_le32(0); + if (pphead->dacl) { + offpacl = le32_to_cpu(pphead->dacl); + ppacl = (const ACL*)&parentattr[offpacl]; + pnacl = (ACL*)&newattr[pos]; + aclsz = ntfs_inherit_acl(ppacl, pnacl, usid, gsid, fordir); + if (aclsz) { + pnhead->dacl = cpu_to_le32(pos); + pos += aclsz; + pnhead->control |= SE_DACL_PRESENT; + } + } + /* + * locate and inherit SACL + */ + pnhead->sacl = const_cpu_to_le32(0); + if (pphead->sacl) { + offpacl = le32_to_cpu(pphead->sacl); + ppacl = (const ACL*)&parentattr[offpacl]; + pnacl = (ACL*)&newattr[pos]; + aclsz = ntfs_inherit_acl(ppacl, pnacl, usid, gsid, fordir); + if (aclsz) { + pnhead->sacl = cpu_to_le32(pos); + pos += aclsz; + pnhead->control |= SE_SACL_PRESENT; + } + } + /* + * inherit or redefine owner + */ + memcpy(&newattr[pos],usid,usidsz); + pnhead->owner = cpu_to_le32(pos); + pos += usidsz; + /* + * inherit or redefine group + */ + memcpy(&newattr[pos],gsid,gsidsz); + pnhead->group = cpu_to_le32(pos); + pos += usidsz; + securid = setsecurityattr(scx->vol, + (SECURITY_DESCRIPTOR_RELATIVE*)newattr, pos); + free(newattr); + } else + securid = const_cpu_to_le32(0); + return (securid); +} + +/* + * Get an inherited security id + * + * For Windows compatibility, the normal initial permission setting + * may be inherited from the parent directory instead of being + * defined by the creation arguments. + * + * The following creates an inherited id for that purpose. + * + * Note : the owner and group of parent directory are also + * inherited (which is not the case on Windows) if no user mapping + * is defined. + * + * Returns the inherited id, or zero if not possible (eg on NTFS 1.x) + */ + +le32 ntfs_inherited_id(struct SECURITY_CONTEXT *scx, + ntfs_inode *dir_ni, BOOL fordir) +{ + struct CACHED_PERMISSIONS *cached; + char *parentattr; + le32 securid; + + securid = const_cpu_to_le32(0); + cached = (struct CACHED_PERMISSIONS*)NULL; + /* + * Try to get inherited id from cache + */ + if (test_nino_flag(dir_ni, v3_Extensions) + && dir_ni->security_id) { + cached = fetch_cache(scx, dir_ni); + if (cached) + securid = (fordir ? cached->inh_dirid + : cached->inh_fileid); + } + /* + * Not cached or not available in cache, compute it all + * Note : if parent directory has no id, it is not cacheable + */ + if (!securid) { + parentattr = getsecurityattr(scx->vol, dir_ni); + if (parentattr) { + securid = build_inherited_id(scx, + parentattr, fordir); + free(parentattr); + /* + * Store the result into cache for further use + */ + if (securid) { + cached = fetch_cache(scx, dir_ni); + if (cached) { + if (fordir) + cached->inh_dirid = securid; + else + cached->inh_fileid = securid; + } + } + } + } + return (securid); +} + +/* + * Link a group to a member of group + * + * Returns 0 if OK, -1 (and errno set) if error + */ + +static int link_single_group(struct MAPPING *usermapping, struct passwd *user, + gid_t gid) +{ + struct group *group; + char **grmem; + int grcnt; + gid_t *groups; + int res; + + res = 0; + group = getgrgid(gid); + if (group && group->gr_mem) { + grcnt = usermapping->grcnt; + groups = usermapping->groups; + grmem = group->gr_mem; + while (*grmem && strcmp(user->pw_name, *grmem)) + grmem++; + if (*grmem) { + if (!grcnt) + groups = (gid_t*)malloc(sizeof(gid_t)); + else + groups = (gid_t*)realloc(groups, + (grcnt+1)*sizeof(gid_t)); + if (groups) + groups[grcnt++] = gid; + else { + res = -1; + errno = ENOMEM; + } + } + usermapping->grcnt = grcnt; + usermapping->groups = groups; + } + return (res); +} + + +/* + * Statically link group to users + * This is based on groups defined in /etc/group and does not take + * the groups dynamically set by setgroups() nor any changes in + * /etc/group into account + * + * Only mapped groups and root group are linked to mapped users + * + * Returns 0 if OK, -1 (and errno set) if error + * + */ + +static int link_group_members(struct SECURITY_CONTEXT *scx) +{ + struct MAPPING *usermapping; + struct MAPPING *groupmapping; + struct passwd *user; + int res; + + res = 0; + for (usermapping=scx->mapping[MAPUSERS]; usermapping && !res; + usermapping=usermapping->next) { + usermapping->grcnt = 0; + usermapping->groups = (gid_t*)NULL; + user = getpwuid(usermapping->xid); + if (user && user->pw_name) { + for (groupmapping=scx->mapping[MAPGROUPS]; + groupmapping && !res; + groupmapping=groupmapping->next) { + if (link_single_group(usermapping, user, + groupmapping->xid)) + res = -1; + } + if (!res && link_single_group(usermapping, + user, (gid_t)0)) + res = -1; + } + } + return (res); +} + + +/* + * Apply default single user mapping + * returns zero if successful + */ + +static int ntfs_do_default_mapping(struct SECURITY_CONTEXT *scx, + const SID *usid) +{ + struct MAPPING *usermapping; + struct MAPPING *groupmapping; + SID *sid; + int sidsz; + int res; + + res = -1; + sidsz = ntfs_sid_size(usid); + sid = (SID*)ntfs_malloc(sidsz); + if (sid) { + memcpy(sid,usid,sidsz); + usermapping = (struct MAPPING*)ntfs_malloc(sizeof(struct MAPPING)); + if (usermapping) { + groupmapping = (struct MAPPING*)ntfs_malloc(sizeof(struct MAPPING)); + if (groupmapping) { + usermapping->sid = sid; + usermapping->xid = scx->uid; + usermapping->next = (struct MAPPING*)NULL; + groupmapping->sid = sid; + groupmapping->xid = scx->uid; + groupmapping->next = (struct MAPPING*)NULL; + scx->mapping[MAPUSERS] = usermapping; + scx->mapping[MAPGROUPS] = groupmapping; + res = 0; + } + } + } + return (res); + +} + +/* + * Make sure there are no ambiguous mapping + * Ambiguous mapping may lead to undesired configurations and + * we had rather be safe until the consequences are understood + */ + +#if 0 /* not activated for now */ + +static BOOL check_mapping(const struct MAPPING *usermapping, + const struct MAPPING *groupmapping) +{ + const struct MAPPING *mapping1; + const struct MAPPING *mapping2; + BOOL ambiguous; + + ambiguous = FALSE; + for (mapping1=usermapping; mapping1; mapping1=mapping1->next) + for (mapping2=mapping1->next; mapping2; mapping1=mapping2->next) + if (ntfs_same_sid(mapping1->sid,mapping2->sid)) { + if (mapping1->xid != mapping2->xid) + ambiguous = TRUE; + } else { + if (mapping1->xid == mapping2->xid) + ambiguous = TRUE; + } + for (mapping1=groupmapping; mapping1; mapping1=mapping1->next) + for (mapping2=mapping1->next; mapping2; mapping1=mapping2->next) + if (ntfs_same_sid(mapping1->sid,mapping2->sid)) { + if (mapping1->xid != mapping2->xid) + ambiguous = TRUE; + } else { + if (mapping1->xid == mapping2->xid) + ambiguous = TRUE; + } + return (ambiguous); +} + +#endif + +/* + * Try and apply default single user mapping + * returns zero if successful + */ + +static int ntfs_default_mapping(struct SECURITY_CONTEXT *scx) +{ + const SECURITY_DESCRIPTOR_RELATIVE *phead; + ntfs_inode *ni; + char *securattr; + const SID *usid; + int res; + + res = -1; + ni = ntfs_pathname_to_inode(scx->vol, NULL, "/."); + if (ni) { + securattr = getsecurityattr(scx->vol, ni); + if (securattr) { + phead = (const SECURITY_DESCRIPTOR_RELATIVE*)securattr; + usid = (SID*)&securattr[le32_to_cpu(phead->owner)]; + if (ntfs_is_user_sid(usid)) + res = ntfs_do_default_mapping(scx,usid); + free(securattr); + } + ntfs_inode_close(ni); + } + return (res); +} + +/* + * Basic read from a user mapping file on another volume + */ + +static int basicread(void *fileid, char *buf, size_t size, off_t offs __attribute__((unused))) +{ + return (read(*(int*)fileid, buf, size)); +} + + +/* + * Read from a user mapping file on current NTFS partition + */ + +static int localread(void *fileid, char *buf, size_t size, off_t offs) +{ + return (ntfs_local_read((ntfs_inode*)fileid, + AT_UNNAMED, 0, buf, size, offs)); +} + +/* + * Build the user mapping + * - according to a mapping file if defined (or default present), + * - or try default single user mapping if possible + * + * The mapping is specific to a mounted device + * No locking done, mounting assumed non multithreaded + * + * returns zero if mapping is successful + * (failure should not be interpreted as an error) + */ + +int ntfs_build_mapping(struct SECURITY_CONTEXT *scx, const char *usermap_path) +{ + struct MAPLIST *item; + struct MAPLIST *firstitem; + struct MAPPING *usermapping; + struct MAPPING *groupmapping; + ntfs_inode *ni; + int fd; + + /* be sure not to map anything until done */ + scx->mapping[MAPUSERS] = (struct MAPPING*)NULL; + scx->mapping[MAPGROUPS] = (struct MAPPING*)NULL; + + if (!usermap_path) usermap_path = MAPPINGFILE; + if (usermap_path[0] == '/') { + fd = open(usermap_path,O_RDONLY); + if (fd > 0) { + firstitem = ntfs_read_mapping(basicread, (void*)&fd); + close(fd); + } else + firstitem = (struct MAPLIST*)NULL; + } else { + ni = ntfs_pathname_to_inode(scx->vol, NULL, usermap_path); + if (ni) { + firstitem = ntfs_read_mapping(localread, ni); + ntfs_inode_close(ni); + } else + firstitem = (struct MAPLIST*)NULL; + } + + + if (firstitem) { + usermapping = ntfs_do_user_mapping(firstitem); + groupmapping = ntfs_do_group_mapping(firstitem); + if (usermapping && groupmapping) { + scx->mapping[MAPUSERS] = usermapping; + scx->mapping[MAPGROUPS] = groupmapping; + } else + ntfs_log_error("There were no valid user or no valid group\n"); + /* now we can free the memory copy of input text */ + /* and rely on internal representation */ + while (firstitem) { + item = firstitem->next; + free(firstitem); + firstitem = item; + } + } else { + /* no mapping file, try default mapping */ + if (scx->uid && scx->gid) { + if (!ntfs_default_mapping(scx)) + ntfs_log_info("Using default user mapping\n"); + } + } + return (!scx->mapping[MAPUSERS] || link_group_members(scx)); +} + +#ifdef HAVE_SETXATTR /* extended attributes interface required */ + +/* + * Get the ntfs attribute into an extended attribute + * The attribute is returned according to cpu endianness + */ + +int ntfs_get_ntfs_attrib(ntfs_inode *ni, char *value, size_t size) +{ + u32 attrib; + size_t outsize; + + outsize = 0; /* default to no data and no error */ + if (ni) { + attrib = le32_to_cpu(ni->flags); + if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) + attrib |= const_le32_to_cpu(FILE_ATTR_DIRECTORY); + else + attrib &= ~const_le32_to_cpu(FILE_ATTR_DIRECTORY); + if (!attrib) + attrib |= const_le32_to_cpu(FILE_ATTR_NORMAL); + outsize = sizeof(FILE_ATTR_FLAGS); + if (size >= outsize) { + if (value) + memcpy(value,&attrib,outsize); + else + errno = EINVAL; + } + } + return (outsize ? (int)outsize : -errno); +} + +/* + * Return the ntfs attribute into an extended attribute + * The attribute is expected according to cpu endianness + * + * Returns 0, or -1 if there is a problem + */ + +int ntfs_set_ntfs_attrib(ntfs_inode *ni, + const char *value, size_t size, int flags) +{ + u32 attrib; + le32 settable; + ATTR_FLAGS dirflags; + int res; + + res = -1; + if (ni && value && (size >= sizeof(FILE_ATTR_FLAGS))) { + if (!(flags & XATTR_CREATE)) { + /* copy to avoid alignment problems */ + memcpy(&attrib,value,sizeof(FILE_ATTR_FLAGS)); + settable = FILE_ATTR_SETTABLE; + res = 0; + if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) { + /* + * Accept changing compression for a directory + * and set index root accordingly + */ + settable |= FILE_ATTR_COMPRESSED; + if ((ni->flags ^ cpu_to_le32(attrib)) + & FILE_ATTR_COMPRESSED) { + if (ni->flags & FILE_ATTR_COMPRESSED) + dirflags = const_cpu_to_le16(0); + else + dirflags = ATTR_IS_COMPRESSED; + res = ntfs_attr_set_flags(ni, + AT_INDEX_ROOT, + NTFS_INDEX_I30, 4, + dirflags, + ATTR_COMPRESSION_MASK); + } + } + if (!res) { + ni->flags = (ni->flags & ~settable) + | (cpu_to_le32(attrib) & settable); + NInoFileNameSetDirty(ni); + NInoSetDirty(ni); + } + } else + errno = EEXIST; + } else + errno = EINVAL; + return (res ? -1 : 0); +} + +#endif /* HAVE_SETXATTR */ + +/* + * Open $Secure once for all + * returns zero if it succeeds + * non-zero if it fails. This is not an error (on NTFS v1.x) + */ + + +int ntfs_open_secure(ntfs_volume *vol) +{ + ntfs_inode *ni; + int res; + + res = -1; + vol->secure_ni = (ntfs_inode*)NULL; + vol->secure_xsii = (ntfs_index_context*)NULL; + vol->secure_xsdh = (ntfs_index_context*)NULL; + if (vol->major_ver >= 3) { + /* make sure this is a genuine $Secure inode 9 */ + ni = ntfs_pathname_to_inode(vol, NULL, "$Secure"); + if (ni && (ni->mft_no == 9)) { + vol->secure_reentry = 0; + vol->secure_xsii = ntfs_index_ctx_get(ni, + sii_stream, 4); + vol->secure_xsdh = ntfs_index_ctx_get(ni, + sdh_stream, 4); + if (ni && vol->secure_xsii && vol->secure_xsdh) { + vol->secure_ni = ni; + res = 0; + } + } + } + return (res); +} + +/* + * Final cleaning + * Allocated memory is freed to facilitate the detection of memory leaks + */ + +void ntfs_close_secure(struct SECURITY_CONTEXT *scx) +{ + ntfs_volume *vol; + + vol = scx->vol; + if (vol->secure_ni) { + ntfs_index_ctx_put(vol->secure_xsii); + ntfs_index_ctx_put(vol->secure_xsdh); + ntfs_inode_close(vol->secure_ni); + + } + ntfs_free_mapping(scx->mapping); + free_caches(scx); +} + +/* + * API for direct access to security descriptors + * based on Win32 API + */ + + +/* + * Selective feeding of a security descriptor into user buffer + * + * Returns TRUE if successful + */ + +static BOOL feedsecurityattr(const char *attr, u32 selection, + char *buf, u32 buflen, u32 *psize) +{ + const SECURITY_DESCRIPTOR_RELATIVE *phead; + SECURITY_DESCRIPTOR_RELATIVE *pnhead; + const ACL *pdacl; + const ACL *psacl; + const SID *pusid; + const SID *pgsid; + unsigned int offdacl; + unsigned int offsacl; + unsigned int offowner; + unsigned int offgroup; + unsigned int daclsz; + unsigned int saclsz; + unsigned int usidsz; + unsigned int gsidsz; + unsigned int size; /* size of requested attributes */ + BOOL ok; + unsigned int pos; + unsigned int avail; + le16 control; + + avail = 0; + control = SE_SELF_RELATIVE; + phead = (const SECURITY_DESCRIPTOR_RELATIVE*)attr; + size = sizeof(SECURITY_DESCRIPTOR_RELATIVE); + + /* locate DACL if requested and available */ + if (phead->dacl && (selection & DACL_SECURITY_INFORMATION)) { + offdacl = le32_to_cpu(phead->dacl); + pdacl = (const ACL*)&attr[offdacl]; + daclsz = le16_to_cpu(pdacl->size); + size += daclsz; + avail |= DACL_SECURITY_INFORMATION; + } else + offdacl = daclsz = 0; + + /* locate owner if requested and available */ + offowner = le32_to_cpu(phead->owner); + if (offowner && (selection & OWNER_SECURITY_INFORMATION)) { + /* find end of USID */ + pusid = (const SID*)&attr[offowner]; + usidsz = ntfs_sid_size(pusid); + size += usidsz; + avail |= OWNER_SECURITY_INFORMATION; + } else + offowner = usidsz = 0; + + /* locate group if requested and available */ + offgroup = le32_to_cpu(phead->group); + if (offgroup && (selection & GROUP_SECURITY_INFORMATION)) { + /* find end of GSID */ + pgsid = (const SID*)&attr[offgroup]; + gsidsz = ntfs_sid_size(pgsid); + size += gsidsz; + avail |= GROUP_SECURITY_INFORMATION; + } else + offgroup = gsidsz = 0; + + /* locate SACL if requested and available */ + if (phead->sacl && (selection & SACL_SECURITY_INFORMATION)) { + /* find end of SACL */ + offsacl = le32_to_cpu(phead->sacl); + psacl = (const ACL*)&attr[offsacl]; + saclsz = le16_to_cpu(psacl->size); + size += saclsz; + avail |= SACL_SECURITY_INFORMATION; + } else + offsacl = saclsz = 0; + + /* + * Check having enough size in destination buffer + * (required size is returned nevertheless so that + * the request can be reissued with adequate size) + */ + if (size > buflen) { + *psize = size; + errno = EINVAL; + ok = FALSE; + } else { + if (selection & OWNER_SECURITY_INFORMATION) + control |= phead->control & SE_OWNER_DEFAULTED; + if (selection & GROUP_SECURITY_INFORMATION) + control |= phead->control & SE_GROUP_DEFAULTED; + if (selection & DACL_SECURITY_INFORMATION) + control |= phead->control + & (SE_DACL_PRESENT + | SE_DACL_DEFAULTED + | SE_DACL_AUTO_INHERITED + | SE_DACL_PROTECTED); + if (selection & SACL_SECURITY_INFORMATION) + control |= phead->control + & (SE_SACL_PRESENT + | SE_SACL_DEFAULTED + | SE_SACL_AUTO_INHERITED + | SE_SACL_PROTECTED); + /* + * copy header and feed new flags, even if no detailed data + */ + memcpy(buf,attr,sizeof(SECURITY_DESCRIPTOR_RELATIVE)); + pnhead = (SECURITY_DESCRIPTOR_RELATIVE*)buf; + pnhead->control = control; + pos = sizeof(SECURITY_DESCRIPTOR_RELATIVE); + + /* copy DACL if requested and available */ + if (selection & avail & DACL_SECURITY_INFORMATION) { + pnhead->dacl = cpu_to_le32(pos); + memcpy(&buf[pos],&attr[offdacl],daclsz); + pos += daclsz; + } else + pnhead->dacl = const_cpu_to_le32(0); + + /* copy SACL if requested and available */ + if (selection & avail & SACL_SECURITY_INFORMATION) { + pnhead->sacl = cpu_to_le32(pos); + memcpy(&buf[pos],&attr[offsacl],saclsz); + pos += saclsz; + } else + pnhead->sacl = const_cpu_to_le32(0); + + /* copy owner if requested and available */ + if (selection & avail & OWNER_SECURITY_INFORMATION) { + pnhead->owner = cpu_to_le32(pos); + memcpy(&buf[pos],&attr[offowner],usidsz); + pos += usidsz; + } else + pnhead->owner = const_cpu_to_le32(0); + + /* copy group if requested and available */ + if (selection & avail & GROUP_SECURITY_INFORMATION) { + pnhead->group = cpu_to_le32(pos); + memcpy(&buf[pos],&attr[offgroup],gsidsz); + pos += gsidsz; + } else + pnhead->group = const_cpu_to_le32(0); + if (pos != size) + ntfs_log_error("Error in security descriptor size\n"); + *psize = size; + ok = TRUE; + } + + return (ok); +} + +/* + * Merge a new security descriptor into the old one + * and assign to designated file + * + * Returns TRUE if successful + */ + +static BOOL mergesecurityattr(ntfs_volume *vol, const char *oldattr, + const char *newattr, u32 selection, ntfs_inode *ni) +{ + const SECURITY_DESCRIPTOR_RELATIVE *oldhead; + const SECURITY_DESCRIPTOR_RELATIVE *newhead; + SECURITY_DESCRIPTOR_RELATIVE *targhead; + const ACL *pdacl; + const ACL *psacl; + const SID *powner; + const SID *pgroup; + int offdacl; + int offsacl; + int offowner; + int offgroup; + unsigned int size; + le16 control; + char *target; + int pos; + int oldattrsz; + int newattrsz; + BOOL ok; + + ok = FALSE; /* default return */ + oldhead = (const SECURITY_DESCRIPTOR_RELATIVE*)oldattr; + newhead = (const SECURITY_DESCRIPTOR_RELATIVE*)newattr; + oldattrsz = ntfs_attr_size(oldattr); + newattrsz = ntfs_attr_size(newattr); + target = (char*)ntfs_malloc(oldattrsz + newattrsz); + if (target) { + targhead = (SECURITY_DESCRIPTOR_RELATIVE*)target; + pos = sizeof(SECURITY_DESCRIPTOR_RELATIVE); + control = SE_SELF_RELATIVE; + /* + * copy new DACL if selected + * or keep old DACL if any + */ + if ((selection & DACL_SECURITY_INFORMATION) ? + newhead->dacl : oldhead->dacl) { + if (selection & DACL_SECURITY_INFORMATION) { + offdacl = le32_to_cpu(newhead->dacl); + pdacl = (const ACL*)&newattr[offdacl]; + } else { + offdacl = le32_to_cpu(oldhead->dacl); + pdacl = (const ACL*)&oldattr[offdacl]; + } + size = le16_to_cpu(pdacl->size); + memcpy(&target[pos], pdacl, size); + targhead->dacl = cpu_to_le32(pos); + pos += size; + } else + targhead->dacl = const_cpu_to_le32(0); + if (selection & DACL_SECURITY_INFORMATION) { + control |= newhead->control + & (SE_DACL_PRESENT + | SE_DACL_DEFAULTED + | SE_DACL_PROTECTED); + if (newhead->control & SE_DACL_AUTO_INHERIT_REQ) + control |= SE_DACL_AUTO_INHERITED; + } else + control |= oldhead->control + & (SE_DACL_PRESENT + | SE_DACL_DEFAULTED + | SE_DACL_AUTO_INHERITED + | SE_DACL_PROTECTED); + /* + * copy new SACL if selected + * or keep old SACL if any + */ + if ((selection & SACL_SECURITY_INFORMATION) ? + newhead->sacl : oldhead->sacl) { + if (selection & SACL_SECURITY_INFORMATION) { + offsacl = le32_to_cpu(newhead->sacl); + psacl = (const ACL*)&newattr[offsacl]; + } else { + offsacl = le32_to_cpu(oldhead->sacl); + psacl = (const ACL*)&oldattr[offsacl]; + } + size = le16_to_cpu(psacl->size); + memcpy(&target[pos], psacl, size); + targhead->sacl = cpu_to_le32(pos); + pos += size; + } else + targhead->sacl = const_cpu_to_le32(0); + if (selection & SACL_SECURITY_INFORMATION) { + control |= newhead->control + & (SE_SACL_PRESENT + | SE_SACL_DEFAULTED + | SE_SACL_PROTECTED); + if (newhead->control & SE_SACL_AUTO_INHERIT_REQ) + control |= SE_SACL_AUTO_INHERITED; + } else + control |= oldhead->control + & (SE_SACL_PRESENT + | SE_SACL_DEFAULTED + | SE_SACL_AUTO_INHERITED + | SE_SACL_PROTECTED); + /* + * copy new OWNER if selected + * or keep old OWNER if any + */ + if ((selection & OWNER_SECURITY_INFORMATION) ? + newhead->owner : oldhead->owner) { + if (selection & OWNER_SECURITY_INFORMATION) { + offowner = le32_to_cpu(newhead->owner); + powner = (const SID*)&newattr[offowner]; + } else { + offowner = le32_to_cpu(oldhead->owner); + powner = (const SID*)&oldattr[offowner]; + } + size = ntfs_sid_size(powner); + memcpy(&target[pos], powner, size); + targhead->owner = cpu_to_le32(pos); + pos += size; + } else + targhead->owner = const_cpu_to_le32(0); + if (selection & OWNER_SECURITY_INFORMATION) + control |= newhead->control & SE_OWNER_DEFAULTED; + else + control |= oldhead->control & SE_OWNER_DEFAULTED; + /* + * copy new GROUP if selected + * or keep old GROUP if any + */ + if ((selection & GROUP_SECURITY_INFORMATION) ? + newhead->group : oldhead->group) { + if (selection & GROUP_SECURITY_INFORMATION) { + offgroup = le32_to_cpu(newhead->group); + pgroup = (const SID*)&newattr[offgroup]; + control |= newhead->control + & SE_GROUP_DEFAULTED; + } else { + offgroup = le32_to_cpu(oldhead->group); + pgroup = (const SID*)&oldattr[offgroup]; + control |= oldhead->control + & SE_GROUP_DEFAULTED; + } + size = ntfs_sid_size(pgroup); + memcpy(&target[pos], pgroup, size); + targhead->group = cpu_to_le32(pos); + pos += size; + } else + targhead->group = const_cpu_to_le32(0); + if (selection & GROUP_SECURITY_INFORMATION) + control |= newhead->control & SE_GROUP_DEFAULTED; + else + control |= oldhead->control & SE_GROUP_DEFAULTED; + targhead->revision = SECURITY_DESCRIPTOR_REVISION; + targhead->alignment = 0; + targhead->control = control; + ok = !update_secur_descr(vol, target, ni); + free(target); + } + return (ok); +} + +/* + * Return the security descriptor of a file + * This is intended to be similar to GetFileSecurity() from Win32 + * in order to facilitate the development of portable tools + * + * returns zero if unsuccessful (following Win32 conventions) + * -1 if no securid + * the securid if any + * + * The Win32 API is : + * + * BOOL WINAPI GetFileSecurity( + * __in LPCTSTR lpFileName, + * __in SECURITY_INFORMATION RequestedInformation, + * __out_opt PSECURITY_DESCRIPTOR pSecurityDescriptor, + * __in DWORD nLength, + * __out LPDWORD lpnLengthNeeded + * ); + * + */ + +int ntfs_get_file_security(struct SECURITY_API *scapi, + const char *path, u32 selection, + char *buf, u32 buflen, u32 *psize) +{ + ntfs_inode *ni; + char *attr; + int res; + + res = 0; /* default return */ + if (scapi && (scapi->magic == MAGIC_API)) { + ni = ntfs_pathname_to_inode(scapi->security.vol, NULL, path); + if (ni) { + attr = getsecurityattr(scapi->security.vol, ni); + if (attr) { + if (feedsecurityattr(attr,selection, + buf,buflen,psize)) { + if (test_nino_flag(ni, v3_Extensions) + && ni->security_id) + res = le32_to_cpu( + ni->security_id); + else + res = -1; + } + free(attr); + } + ntfs_inode_close(ni); + } else + errno = ENOENT; + if (!res) *psize = 0; + } else + errno = EINVAL; /* do not clear *psize */ + return (res); +} + + +/* + * Set the security descriptor of a file or directory + * This is intended to be similar to SetFileSecurity() from Win32 + * in order to facilitate the development of portable tools + * + * returns zero if unsuccessful (following Win32 conventions) + * -1 if no securid + * the securid if any + * + * The Win32 API is : + * + * BOOL WINAPI SetFileSecurity( + * __in LPCTSTR lpFileName, + * __in SECURITY_INFORMATION SecurityInformation, + * __in PSECURITY_DESCRIPTOR pSecurityDescriptor + * ); + */ + +int ntfs_set_file_security(struct SECURITY_API *scapi, + const char *path, u32 selection, const char *attr) +{ + const SECURITY_DESCRIPTOR_RELATIVE *phead; + ntfs_inode *ni; + int attrsz; + BOOL missing; + char *oldattr; + int res; + + res = 0; /* default return */ + if (scapi && (scapi->magic == MAGIC_API) && attr) { + phead = (const SECURITY_DESCRIPTOR_RELATIVE*)attr; + attrsz = ntfs_attr_size(attr); + /* if selected, owner and group must be present or defaulted */ + missing = ((selection & OWNER_SECURITY_INFORMATION) + && !phead->owner + && !(phead->control & SE_OWNER_DEFAULTED)) + || ((selection & GROUP_SECURITY_INFORMATION) + && !phead->group + && !(phead->control & SE_GROUP_DEFAULTED)); + if (!missing + && (phead->control & SE_SELF_RELATIVE) + && ntfs_valid_descr(attr, attrsz)) { + ni = ntfs_pathname_to_inode(scapi->security.vol, + NULL, path); + if (ni) { + oldattr = getsecurityattr(scapi->security.vol, + ni); + if (oldattr) { + if (mergesecurityattr( + scapi->security.vol, + oldattr, attr, + selection, ni)) { + if (test_nino_flag(ni, + v3_Extensions)) + res = le32_to_cpu( + ni->security_id); + else + res = -1; + } + free(oldattr); + } + ntfs_inode_close(ni); + } + } else + errno = EINVAL; + } else + errno = EINVAL; + return (res); +} + + +/* + * Return the attributes of a file + * This is intended to be similar to GetFileAttributes() from Win32 + * in order to facilitate the development of portable tools + * + * returns -1 if unsuccessful (Win32 : INVALID_FILE_ATTRIBUTES) + * + * The Win32 API is : + * + * DWORD WINAPI GetFileAttributes( + * __in LPCTSTR lpFileName + * ); + */ + +int ntfs_get_file_attributes(struct SECURITY_API *scapi, const char *path) +{ + ntfs_inode *ni; + s32 attrib; + + attrib = -1; /* default return */ + if (scapi && (scapi->magic == MAGIC_API) && path) { + ni = ntfs_pathname_to_inode(scapi->security.vol, NULL, path); + if (ni) { + attrib = le32_to_cpu(ni->flags); + if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) + attrib |= const_le32_to_cpu(FILE_ATTR_DIRECTORY); + else + attrib &= ~const_le32_to_cpu(FILE_ATTR_DIRECTORY); + if (!attrib) + attrib |= const_le32_to_cpu(FILE_ATTR_NORMAL); + + ntfs_inode_close(ni); + } else + errno = ENOENT; + } else + errno = EINVAL; /* do not clear *psize */ + return (attrib); +} + + +/* + * Set attributes to a file or directory + * This is intended to be similar to SetFileAttributes() from Win32 + * in order to facilitate the development of portable tools + * + * Only a few flags can be set (same list as Win32) + * + * returns zero if unsuccessful (following Win32 conventions) + * nonzero if successful + * + * The Win32 API is : + * + * BOOL WINAPI SetFileAttributes( + * __in LPCTSTR lpFileName, + * __in DWORD dwFileAttributes + * ); + */ + +BOOL ntfs_set_file_attributes(struct SECURITY_API *scapi, + const char *path, s32 attrib) +{ + ntfs_inode *ni; + le32 settable; + ATTR_FLAGS dirflags; + int res; + + res = 0; /* default return */ + if (scapi && (scapi->magic == MAGIC_API) && path) { + ni = ntfs_pathname_to_inode(scapi->security.vol, NULL, path); + if (ni) { + settable = FILE_ATTR_SETTABLE; + if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) { + /* + * Accept changing compression for a directory + * and set index root accordingly + */ + settable |= FILE_ATTR_COMPRESSED; + if ((ni->flags ^ cpu_to_le32(attrib)) + & FILE_ATTR_COMPRESSED) { + if (ni->flags & FILE_ATTR_COMPRESSED) + dirflags = const_cpu_to_le16(0); + else + dirflags = ATTR_IS_COMPRESSED; + res = ntfs_attr_set_flags(ni, + AT_INDEX_ROOT, + NTFS_INDEX_I30, 4, + dirflags, + ATTR_COMPRESSION_MASK); + } + } + if (!res) { + ni->flags = (ni->flags & ~settable) + | (cpu_to_le32(attrib) & settable); + NInoSetDirty(ni); + } + if (!ntfs_inode_close(ni)) + res = -1; + } else + errno = ENOENT; + } + return (res); +} + + +BOOL ntfs_read_directory(struct SECURITY_API *scapi, + const char *path, ntfs_filldir_t callback, void *context) +{ + ntfs_inode *ni; + BOOL ok; + s64 pos; + + ok = FALSE; /* default return */ + if (scapi && (scapi->magic == MAGIC_API) && callback) { + ni = ntfs_pathname_to_inode(scapi->security.vol, NULL, path); + if (ni) { + if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) { + pos = 0; + ntfs_readdir(ni,&pos,context,callback); + ok = !ntfs_inode_close(ni); + } else { + ntfs_inode_close(ni); + errno = ENOTDIR; + } + } else + errno = ENOENT; + } else + errno = EINVAL; /* do not clear *psize */ + return (ok); +} + +/* + * read $SDS (for auditing security data) + * + * Returns the number or read bytes, or -1 if there is an error + */ + +int ntfs_read_sds(struct SECURITY_API *scapi, + char *buf, u32 size, u32 offset) +{ + int got; + + got = -1; /* default return */ + if (scapi && (scapi->magic == MAGIC_API)) { + if (scapi->security.vol->secure_ni) + got = ntfs_local_read(scapi->security.vol->secure_ni, + STREAM_SDS, 4, buf, size, offset); + else + errno = EOPNOTSUPP; + } else + errno = EINVAL; + return (got); +} + +/* + * read $SII (for auditing security data) + * + * Returns next entry, or NULL if there is an error + */ + +INDEX_ENTRY *ntfs_read_sii(struct SECURITY_API *scapi, + INDEX_ENTRY *entry) +{ + SII_INDEX_KEY key; + INDEX_ENTRY *ret; + BOOL found; + ntfs_index_context *xsii; + + ret = (INDEX_ENTRY*)NULL; /* default return */ + if (scapi && (scapi->magic == MAGIC_API)) { + xsii = scapi->security.vol->secure_xsii; + if (xsii) { + if (!entry) { + key.security_id = const_cpu_to_le32(0); + found = !ntfs_index_lookup((char*)&key, + sizeof(SII_INDEX_KEY), xsii); + /* not supposed to find */ + if (!found && (errno == ENOENT)) + ret = xsii->entry; + } else + ret = ntfs_index_next(entry,xsii); + if (!ret) + errno = ENODATA; + } else + errno = EOPNOTSUPP; + } else + errno = EINVAL; + return (ret); +} + +/* + * read $SDH (for auditing security data) + * + * Returns next entry, or NULL if there is an error + */ + +INDEX_ENTRY *ntfs_read_sdh(struct SECURITY_API *scapi, + INDEX_ENTRY *entry) +{ + SDH_INDEX_KEY key; + INDEX_ENTRY *ret; + BOOL found; + ntfs_index_context *xsdh; + + ret = (INDEX_ENTRY*)NULL; /* default return */ + if (scapi && (scapi->magic == MAGIC_API)) { + xsdh = scapi->security.vol->secure_xsdh; + if (xsdh) { + if (!entry) { + key.hash = const_cpu_to_le32(0); + key.security_id = const_cpu_to_le32(0); + found = !ntfs_index_lookup((char*)&key, + sizeof(SDH_INDEX_KEY), xsdh); + /* not supposed to find */ + if (!found && (errno == ENOENT)) + ret = xsdh->entry; + } else + ret = ntfs_index_next(entry,xsdh); + if (!ret) + errno = ENODATA; + } else errno = ENOTSUP; + } else + errno = EINVAL; + return (ret); +} + +/* + * Get the mapped user SID + * A buffer of 40 bytes has to be supplied + * + * returns the size of the SID, or zero and errno set if not found + */ + +int ntfs_get_usid(struct SECURITY_API *scapi, uid_t uid, char *buf) +{ + const SID *usid; + BIGSID defusid; + int size; + + size = 0; + if (scapi && (scapi->magic == MAGIC_API)) { + usid = ntfs_find_usid(scapi->security.mapping[MAPUSERS], uid, (SID*)&defusid); + if (usid) { + size = ntfs_sid_size(usid); + memcpy(buf,usid,size); + } else + errno = ENODATA; + } else + errno = EINVAL; + return (size); +} + +/* + * Get the mapped group SID + * A buffer of 40 bytes has to be supplied + * + * returns the size of the SID, or zero and errno set if not found + */ + +int ntfs_get_gsid(struct SECURITY_API *scapi, gid_t gid, char *buf) +{ + const SID *gsid; + BIGSID defgsid; + int size; + + size = 0; + if (scapi && (scapi->magic == MAGIC_API)) { + gsid = ntfs_find_gsid(scapi->security.mapping[MAPGROUPS], gid, (SID*)&defgsid); + if (gsid) { + size = ntfs_sid_size(gsid); + memcpy(buf,gsid,size); + } else + errno = ENODATA; + } else + errno = EINVAL; + return (size); +} + +/* + * Get the user mapped to a SID + * + * returns the uid, or -1 if not found + */ + +int ntfs_get_user(struct SECURITY_API *scapi, const SID *usid) +{ + int uid; + + uid = -1; + if (scapi && (scapi->magic == MAGIC_API) && ntfs_valid_sid(usid)) { + if (ntfs_same_sid(usid,adminsid)) + uid = 0; + else { + uid = ntfs_find_user(scapi->security.mapping[MAPUSERS], usid); + if (!uid) { + uid = -1; + errno = ENODATA; + } + } + } else + errno = EINVAL; + return (uid); +} + +/* + * Get the group mapped to a SID + * + * returns the uid, or -1 if not found + */ + +int ntfs_get_group(struct SECURITY_API *scapi, const SID *gsid) +{ + int gid; + + gid = -1; + if (scapi && (scapi->magic == MAGIC_API) && ntfs_valid_sid(gsid)) { + if (ntfs_same_sid(gsid,adminsid)) + gid = 0; + else { + gid = ntfs_find_group(scapi->security.mapping[MAPGROUPS], gsid); + if (!gid) { + gid = -1; + errno = ENODATA; + } + } + } else + errno = EINVAL; + return (gid); +} + +/* + * Initializations before calling ntfs_get_file_security() + * ntfs_set_file_security() and ntfs_read_directory() + * + * Only allowed for root + * + * Returns an (obscured) struct SECURITY_API* needed for further calls + * NULL if not root (EPERM) or device is mounted (EBUSY) + */ + +struct SECURITY_API *ntfs_initialize_file_security(const char *device, + int flags) +{ + ntfs_volume *vol; + unsigned long mntflag; + int mnt; + struct SECURITY_API *scapi; + struct SECURITY_CONTEXT *scx; + + scapi = (struct SECURITY_API*)NULL; + mnt = ntfs_check_if_mounted(device, &mntflag); + if (!mnt && !(mntflag & NTFS_MF_MOUNTED) && !getuid()) { + vol = ntfs_mount(device, flags); + if (vol) { + scapi = (struct SECURITY_API*) + ntfs_malloc(sizeof(struct SECURITY_API)); + if (!ntfs_volume_get_free_space(vol) + && scapi) { + scapi->magic = MAGIC_API; + scapi->seccache = (struct PERMISSIONS_CACHE*)NULL; + scx = &scapi->security; + scx->vol = vol; + scx->uid = getuid(); + scx->gid = getgid(); + scx->pseccache = &scapi->seccache; + scx->vol->secure_flags = 0; + /* accept no mapping and no $Secure */ + ntfs_build_mapping(scx,(const char*)NULL); + ntfs_open_secure(vol); + } else { + if (scapi) + free(scapi); + else + errno = ENOMEM; + mnt = ntfs_umount(vol,FALSE); + scapi = (struct SECURITY_API*)NULL; + } + } + } else + if (getuid()) + errno = EPERM; + else + errno = EBUSY; + return (scapi); +} + +/* + * Leaving after ntfs_initialize_file_security() + * + * Returns FALSE if FAILED + */ + +BOOL ntfs_leave_file_security(struct SECURITY_API *scapi) +{ + int ok; + ntfs_volume *vol; + + ok = FALSE; + if (scapi && (scapi->magic == MAGIC_API) && scapi->security.vol) { + vol = scapi->security.vol; + ntfs_close_secure(&scapi->security); + free(scapi); + if (!ntfs_umount(vol, 0)) + ok = TRUE; + } + return (ok); +} + diff --git a/libntfs-3g/unistr.c b/libntfs-3g/unistr.c new file mode 100755 index 0000000..e65df99 --- a/dev/null +++ b/libntfs-3g/unistr.c @@ -0,0 +1,1321 @@ +/** + * unistr.c - Unicode string handling. Originated from the Linux-NTFS project. + * + * Copyright (c) 2000-2004 Anton Altaparmakov + * Copyright (c) 2002-2009 Szabolcs Szakacsits + * Copyright (c) 2008-2009 Jean-Pierre Andre + * Copyright (c) 2008 Bernhard Kaindl + * + * This program/include file 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/include file 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 (in the main directory of the NTFS-3G + * distribution in the file COPYING); if not, write to the Free Software + * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_STDIO_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_WCHAR_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_ERRNO_H +#include +#endif +#ifdef HAVE_LOCALE_H +#include +#endif + +#if defined(__APPLE__) || defined(__DARWIN__) +#ifdef ENABLE_NFCONV +#include +#endif /* ENABLE_NFCONV */ +#endif /* defined(__APPLE__) || defined(__DARWIN__) */ + +#include "compat.h" +#include "attrib.h" +#include "types.h" +#include "unistr.h" +#include "debug.h" +#include "logging.h" +#include "misc.h" + +#define NOREVBOM 0 /* JPA rejecting U+FFFE and U+FFFF, open to debate */ + +/* + * IMPORTANT + * ========= + * + * All these routines assume that the Unicode characters are in little endian + * encoding inside the strings!!! + */ + +static int use_utf8 = 1; /* use UTF-8 encoding for file names */ + +#if defined(__APPLE__) || defined(__DARWIN__) +#ifdef ENABLE_NFCONV +/** + * This variable controls whether or not automatic normalization form conversion + * should be performed when translating NTFS unicode file names to UTF-8. + * Defaults to on, but can be controlled from the outside using the function + * int ntfs_macosx_normalize_filenames(int normalize); + */ +static int nfconvert_utf8 = 1; +#endif /* ENABLE_NFCONV */ +#endif /* defined(__APPLE__) || defined(__DARWIN__) */ + +/* + * This is used by the name collation functions to quickly determine what + * characters are (in)valid. + */ +#if 0 +static const u8 legal_ansi_char_array[0x40] = { + 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + + 0x17, 0x07, 0x18, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x17, 0x17, 0x18, 0x16, 0x16, 0x17, 0x07, 0x00, + + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x17, 0x17, 0x04, 0x16, 0x18, 0x16, 0x18, 0x18, +}; +#endif + +/** + * ntfs_names_are_equal - compare two Unicode names for equality + * @s1: name to compare to @s2 + * @s1_len: length in Unicode characters of @s1 + * @s2: name to compare to @s1 + * @s2_len: length in Unicode characters of @s2 + * @ic: ignore case bool + * @upcase: upcase table (only if @ic == IGNORE_CASE) + * @upcase_size: length in Unicode characters of @upcase (if present) + * + * Compare the names @s1 and @s2 and return TRUE (1) if the names are + * identical, or FALSE (0) if they are not identical. If @ic is IGNORE_CASE, + * the @upcase table is used to perform a case insensitive comparison. + */ +BOOL ntfs_names_are_equal(const ntfschar *s1, size_t s1_len, + const ntfschar *s2, size_t s2_len, + const IGNORE_CASE_BOOL ic, + const ntfschar *upcase, const u32 upcase_size) +{ + if (s1_len != s2_len) + return FALSE; + if (!s1_len) + return TRUE; + if (ic == CASE_SENSITIVE) + return ntfs_ucsncmp(s1, s2, s1_len) ? FALSE: TRUE; + return ntfs_ucsncasecmp(s1, s2, s1_len, upcase, upcase_size) ? FALSE: + TRUE; +} + +/* + * ntfs_names_full_collate() fully collate two Unicode names + * + * @name1: first Unicode name to compare + * @name1_len: length of first Unicode name to compare + * @name2: second Unicode name to compare + * @name2_len: length of second Unicode name to compare + * @ic: either CASE_SENSITIVE or IGNORE_CASE + * @upcase: upcase table (ignored if @ic is CASE_SENSITIVE) + * @upcase_len: upcase table size (ignored if @ic is CASE_SENSITIVE) + * + * -1 if the first name collates before the second one, + * 0 if the names match, + * 1 if the second name collates before the first one, or + * + */ +int ntfs_names_full_collate(const ntfschar *name1, const u32 name1_len, + const ntfschar *name2, const u32 name2_len, + const IGNORE_CASE_BOOL ic, const ntfschar *upcase, + const u32 upcase_len) +{ + u32 cnt; + u16 c1, c2; + u16 u1, u2; + +#ifdef DEBUG + if (!name1 || !name2 || (ic && (!upcase || !upcase_len))) { + ntfs_log_debug("ntfs_names_collate received NULL pointer!\n"); + exit(1); + } +#endif + cnt = min(name1_len, name2_len); + if (cnt > 0) { + if (ic == CASE_SENSITIVE) { + do { + c1 = le16_to_cpu(*name1); + name1++; + c2 = le16_to_cpu(*name2); + name2++; + } while (--cnt && (c1 == c2)); + u1 = c1; + u2 = c2; + if (u1 < upcase_len) + u1 = le16_to_cpu(upcase[u1]); + if (u2 < upcase_len) + u2 = le16_to_cpu(upcase[u2]); + if ((u1 == u2) && cnt) + do { + u1 = le16_to_cpu(*name1); + name1++; + u2 = le16_to_cpu(*name2); + name2++; + if (u1 < upcase_len) + u1 = le16_to_cpu(upcase[u1]); + if (u2 < upcase_len) + u2 = le16_to_cpu(upcase[u2]); + } while ((u1 == u2) && --cnt); + if (u1 < u2) + return -1; + if (u1 > u2) + return 1; + if (name1_len < name2_len) + return -1; + if (name1_len > name2_len) + return 1; + if (c1 < c2) + return -1; + if (c1 > c2) + return 1; + } else { + do { + u1 = c1 = le16_to_cpu(*name1); + name1++; + u2 = c2 = le16_to_cpu(*name2); + name2++; + if (u1 < upcase_len) + u1 = le16_to_cpu(upcase[u1]); + if (u2 < upcase_len) + u2 = le16_to_cpu(upcase[u2]); + } while ((u1 == u2) && --cnt); + if (u1 < u2) + return -1; + if (u1 > u2) + return 1; + if (name1_len < name2_len) + return -1; + if (name1_len > name2_len) + return 1; + } + } else { + if (name1_len < name2_len) + return -1; + if (name1_len > name2_len) + return 1; + } + return 0; +} + +/** + * ntfs_ucsncmp - compare two little endian Unicode strings + * @s1: first string + * @s2: second string + * @n: maximum unicode characters to compare + * + * Compare the first @n characters of the Unicode strings @s1 and @s2, + * The strings in little endian format and appropriate le16_to_cpu() + * conversion is performed on non-little endian machines. + * + * The function returns an integer less than, equal to, or greater than zero + * if @s1 (or the first @n Unicode characters thereof) is found, respectively, + * to be less than, to match, or be greater than @s2. + */ +int ntfs_ucsncmp(const ntfschar *s1, const ntfschar *s2, size_t n) +{ + ntfschar c1, c2; + size_t i; + +#ifdef DEBUG + if (!s1 || !s2) { + ntfs_log_debug("ntfs_wcsncmp() received NULL pointer!\n"); + exit(1); + } +#endif + for (i = 0; i < n; ++i) { + c1 = le16_to_cpu(s1[i]); + c2 = le16_to_cpu(s2[i]); + if (c1 < c2) + return -1; + if (c1 > c2) + return 1; + if (!c1) + break; + } + return 0; +} + +/** + * ntfs_ucsncasecmp - compare two little endian Unicode strings, ignoring case + * @s1: first string + * @s2: second string + * @n: maximum unicode characters to compare + * @upcase: upcase table + * @upcase_size: upcase table size in Unicode characters + * + * Compare the first @n characters of the Unicode strings @s1 and @s2, + * ignoring case. The strings in little endian format and appropriate + * le16_to_cpu() conversion is performed on non-little endian machines. + * + * Each character is uppercased using the @upcase table before the comparison. + * + * The function returns an integer less than, equal to, or greater than zero + * if @s1 (or the first @n Unicode characters thereof) is found, respectively, + * to be less than, to match, or be greater than @s2. + */ +int ntfs_ucsncasecmp(const ntfschar *s1, const ntfschar *s2, size_t n, + const ntfschar *upcase, const u32 upcase_size) +{ + u16 c1, c2; + size_t i; + +#ifdef DEBUG + if (!s1 || !s2 || !upcase) { + ntfs_log_debug("ntfs_wcsncasecmp() received NULL pointer!\n"); + exit(1); + } +#endif + for (i = 0; i < n; ++i) { + if ((c1 = le16_to_cpu(s1[i])) < upcase_size) + c1 = le16_to_cpu(upcase[c1]); + if ((c2 = le16_to_cpu(s2[i])) < upcase_size) + c2 = le16_to_cpu(upcase[c2]); + if (c1 < c2) + return -1; + if (c1 > c2) + return 1; + if (!c1) + break; + } + return 0; +} + +/** + * ntfs_ucsnlen - determine the length of a little endian Unicode string + * @s: pointer to Unicode string + * @maxlen: maximum length of string @s + * + * Return the number of Unicode characters in the little endian Unicode + * string @s up to a maximum of maxlen Unicode characters, not including + * the terminating (ntfschar)'\0'. If there is no (ntfschar)'\0' between @s + * and @s + @maxlen, @maxlen is returned. + * + * This function never looks beyond @s + @maxlen. + */ +u32 ntfs_ucsnlen(const ntfschar *s, u32 maxlen) +{ + u32 i; + + for (i = 0; i < maxlen; i++) { + if (!le16_to_cpu(s[i])) + break; + } + return i; +} + +/** + * ntfs_ucsndup - duplicate little endian Unicode string + * @s: pointer to Unicode string + * @maxlen: maximum length of string @s + * + * Return a pointer to a new little endian Unicode string which is a duplicate + * of the string s. Memory for the new string is obtained with ntfs_malloc(3), + * and can be freed with free(3). + * + * A maximum of @maxlen Unicode characters are copied and a terminating + * (ntfschar)'\0' little endian Unicode character is added. + * + * This function never looks beyond @s + @maxlen. + * + * Return a pointer to the new little endian Unicode string on success and NULL + * on failure with errno set to the error code. + */ +ntfschar *ntfs_ucsndup(const ntfschar *s, u32 maxlen) +{ + ntfschar *dst; + u32 len; + + len = ntfs_ucsnlen(s, maxlen); + dst = ntfs_malloc((len + 1) * sizeof(ntfschar)); + if (dst) { + memcpy(dst, s, len * sizeof(ntfschar)); + dst[len] = cpu_to_le16(L'\0'); + } + return dst; +} + +/** + * ntfs_name_upcase - Map an Unicode name to its uppercase equivalent + * @name: + * @name_len: + * @upcase: + * @upcase_len: + * + * Description... + * + * Returns: + */ +void ntfs_name_upcase(ntfschar *name, u32 name_len, const ntfschar *upcase, + const u32 upcase_len) +{ + u32 i; + u16 u; + + for (i = 0; i < name_len; i++) + if ((u = le16_to_cpu(name[i])) < upcase_len) + name[i] = upcase[u]; +} + +/** + * ntfs_file_value_upcase - Convert a filename to upper case + * @file_name_attr: + * @upcase: + * @upcase_len: + * + * Description... + * + * Returns: + */ +void ntfs_file_value_upcase(FILE_NAME_ATTR *file_name_attr, + const ntfschar *upcase, const u32 upcase_len) +{ + ntfs_name_upcase((ntfschar*)&file_name_attr->file_name, + file_name_attr->file_name_length, upcase, upcase_len); +} + +/* + NTFS uses Unicode (UTF-16LE [NTFS-3G uses UCS-2LE, which is enough + for now]) for path names, but the Unicode code points need to be + converted before a path can be accessed under NTFS. For 7 bit ASCII/ANSI, + glibc does this even without a locale in a hard-coded fashion as that + appears to be is easy because the low 7-bit ASCII range appears to be + available in all charsets but it does not convert anything if + there was some error with the locale setup or none set up like + when mount is called during early boot where he (by policy) do + not use locales (and may be not available if /usr is not yet mounted), + so this patch fixes the resulting issues for systems which use + UTF-8 and for others, specifying the locale in fstab brings them + the encoding which they want. + + If no locale is defined or there was a problem with setting one + up and whenever nl_langinfo(CODESET) returns a sting starting with + "ANSI", use an internal UCS-2LE <-> UTF-8 codeset converter to fix + the bug where NTFS-3G does not show any path names which include + international characters!!! (and also fails on creating them) as result. + + Author: Bernhard Kaindl + Jean-Pierre Andre made it compliant with RFC3629/RFC2781. +*/ + +/* + * Return the amount of 8-bit elements in UTF-8 needed (without the terminating + * null) to store a given UTF-16LE string. + * + * Return -1 with errno set if string has invalid byte sequence or too long. + */ +static int utf16_to_utf8_size(const ntfschar *ins, const int ins_len, int outs_len) +{ + int i, ret = -1; + int count = 0; + BOOL surrog; + + surrog = FALSE; + for (i = 0; i < ins_len && ins[i]; i++) { + unsigned short c = le16_to_cpu(ins[i]); + if (surrog) { + if ((c >= 0xdc00) && (c < 0xe000)) { + surrog = FALSE; + count += 4; + } else + goto fail; + } else + if (c < 0x80) + count++; + else if (c < 0x800) + count += 2; + else if (c < 0xd800) + count += 3; + else if (c < 0xdc00) + surrog = TRUE; +#if NOREVBOM + else if ((c >= 0xe000) && (c < 0xfffe)) +#else + else if (c >= 0xe000) +#endif + count += 3; + else + goto fail; + if (count > outs_len) { + errno = ENAMETOOLONG; + goto out; + } + } + if (surrog) + goto fail; + + ret = count; +out: + return ret; +fail: + errno = EILSEQ; + goto out; +} + +/* + * ntfs_utf16_to_utf8 - convert a little endian UTF16LE string to an UTF-8 string + * @ins: input utf16 string buffer + * @ins_len: length of input string in utf16 characters + * @outs: on return contains the (allocated) output multibyte string + * @outs_len: length of output buffer in bytes + * + * Return -1 with errno set if string has invalid byte sequence or too long. + */ +static int ntfs_utf16_to_utf8(const ntfschar *ins, const int ins_len, + char **outs, int outs_len) +{ +#if defined(__APPLE__) || defined(__DARWIN__) +#ifdef ENABLE_NFCONV + char *original_outs_value = *outs; + int original_outs_len = outs_len; +#endif /* ENABLE_NFCONV */ +#endif /* defined(__APPLE__) || defined(__DARWIN__) */ + + char *t; + int i, size, ret = -1; + int halfpair; + + halfpair = 0; + if (!*outs) + outs_len = PATH_MAX; + + size = utf16_to_utf8_size(ins, ins_len, outs_len); + + if (size < 0) + goto out; + + if (!*outs) { + outs_len = size + 1; + *outs = ntfs_malloc(outs_len); + if (!*outs) + goto out; + } + + t = *outs; + + for (i = 0; i < ins_len && ins[i]; i++) { + unsigned short c = le16_to_cpu(ins[i]); + /* size not double-checked */ + if (halfpair) { + if ((c >= 0xdc00) && (c < 0xe000)) { + *t++ = 0xf0 + (((halfpair + 64) >> 8) & 7); + *t++ = 0x80 + (((halfpair + 64) >> 2) & 63); + *t++ = 0x80 + ((c >> 6) & 15) + ((halfpair & 3) << 4); + *t++ = 0x80 + (c & 63); + halfpair = 0; + } else + goto fail; + } else if (c < 0x80) { + *t++ = c; + } else { + if (c < 0x800) { + *t++ = (0xc0 | ((c >> 6) & 0x3f)); + *t++ = 0x80 | (c & 0x3f); + } else if (c < 0xd800) { + *t++ = 0xe0 | (c >> 12); + *t++ = 0x80 | ((c >> 6) & 0x3f); + *t++ = 0x80 | (c & 0x3f); + } else if (c < 0xdc00) + halfpair = c; + else if (c >= 0xe000) { + *t++ = 0xe0 | (c >> 12); + *t++ = 0x80 | ((c >> 6) & 0x3f); + *t++ = 0x80 | (c & 0x3f); + } else + goto fail; + } + } + *t = '\0'; + +#if defined(__APPLE__) || defined(__DARWIN__) +#ifdef ENABLE_NFCONV + if(nfconvert_utf8 && (t - *outs) > 0) { + char *new_outs = NULL; + int new_outs_len = ntfs_macosx_normalize_utf8(*outs, &new_outs, 0); // Normalize to decomposed form + if(new_outs_len >= 0 && new_outs != NULL) { + if(original_outs_value != *outs) { + // We have allocated outs ourselves. + free(*outs); + *outs = new_outs; + t = *outs + new_outs_len; + } + else { + // We need to copy new_outs into the fixed outs buffer. + memset(*outs, 0, original_outs_len); + strncpy(*outs, new_outs, original_outs_len-1); + t = *outs + original_outs_len; + free(new_outs); + } + } + else { + ntfs_log_error("Failed to normalize NTFS string to UTF-8 NFD: %s\n", *outs); + ntfs_log_error(" new_outs=0x%p\n", new_outs); + ntfs_log_error(" new_outs_len=%d\n", new_outs_len); + } + } +#endif /* ENABLE_NFCONV */ +#endif /* defined(__APPLE__) || defined(__DARWIN__) */ + + ret = t - *outs; +out: + return ret; +fail: + errno = EILSEQ; + goto out; +} + +/* + * Return the amount of 16-bit elements in UTF-16LE needed + * (without the terminating null) to store given UTF-8 string. + * + * Return -1 with errno set if it's longer than PATH_MAX or string is invalid. + * + * Note: This does not check whether the input sequence is a valid utf8 string, + * and should be used only in context where such check is made! + */ +static int utf8_to_utf16_size(const char *s) +{ + int ret = -1; + unsigned int byte; + size_t count = 0; + + while ((byte = *((const unsigned char *)s++))) { + if (++count >= PATH_MAX) + goto fail; + if (byte >= 0xc0) { + if (byte >= 0xF5) { + errno = EILSEQ; + goto out; + } + if (!*s) + break; + if (byte >= 0xC0) + s++; + if (!*s) + break; + if (byte >= 0xE0) + s++; + if (!*s) + break; + if (byte >= 0xF0) { + s++; + if (++count >= PATH_MAX) + goto fail; + } + } + } + ret = count; +out: + return ret; +fail: + errno = ENAMETOOLONG; + goto out; +} +/* + * This converts one UTF-8 sequence to cpu-endian Unicode value + * within range U+0 .. U+10ffff and excluding U+D800 .. U+DFFF + * + * Return the number of used utf8 bytes or -1 with errno set + * if sequence is invalid. + */ +static int utf8_to_unicode(u32 *wc, const char *s) +{ + unsigned int byte = *((const unsigned char *)s); + + /* single byte */ + if (byte == 0) { + *wc = (u32) 0; + return 0; + } else if (byte < 0x80) { + *wc = (u32) byte; + return 1; + /* double byte */ + } else if (byte < 0xc2) { + goto fail; + } else if (byte < 0xE0) { + if ((s[1] & 0xC0) == 0x80) { + *wc = ((u32)(byte & 0x1F) << 6) + | ((u32)(s[1] & 0x3F)); + return 2; + } else + goto fail; + /* three-byte */ + } else if (byte < 0xF0) { + if (((s[1] & 0xC0) == 0x80) && ((s[2] & 0xC0) == 0x80)) { + *wc = ((u32)(byte & 0x0F) << 12) + | ((u32)(s[1] & 0x3F) << 6) + | ((u32)(s[2] & 0x3F)); + /* Check valid ranges */ +#if NOREVBOM + if (((*wc >= 0x800) && (*wc <= 0xD7FF)) + || ((*wc >= 0xe000) && (*wc <= 0xFFFD))) + return 3; +#else + if (((*wc >= 0x800) && (*wc <= 0xD7FF)) + || ((*wc >= 0xe000) && (*wc <= 0xFFFF))) + return 3; +#endif + } + goto fail; + /* four-byte */ + } else if (byte < 0xF5) { + if (((s[1] & 0xC0) == 0x80) && ((s[2] & 0xC0) == 0x80) + && ((s[3] & 0xC0) == 0x80)) { + *wc = ((u32)(byte & 0x07) << 18) + | ((u32)(s[1] & 0x3F) << 12) + | ((u32)(s[2] & 0x3F) << 6) + | ((u32)(s[3] & 0x3F)); + /* Check valid ranges */ + if ((*wc <= 0x10ffff) && (*wc >= 0x10000)) + return 4; + } + goto fail; + } +fail: + errno = EILSEQ; + return -1; +} + +/** + * ntfs_utf8_to_utf16 - convert a UTF-8 string to a UTF-16LE string + * @ins: input multibyte string buffer + * @outs: on return contains the (allocated) output utf16 string + * @outs_len: length of output buffer in utf16 characters + * + * Return -1 with errno set. + */ +static int ntfs_utf8_to_utf16(const char *ins, ntfschar **outs) +{ +#if defined(__APPLE__) || defined(__DARWIN__) +#ifdef ENABLE_NFCONV + char *new_ins = NULL; + if(nfconvert_utf8) { + int new_ins_len; + new_ins_len = ntfs_macosx_normalize_utf8(ins, &new_ins, 1); // Normalize to composed form + if(new_ins_len >= 0) + ins = new_ins; + else + ntfs_log_error("Failed to normalize NTFS string to UTF-8 NFC: %s\n", ins); + } +#endif /* ENABLE_NFCONV */ +#endif /* defined(__APPLE__) || defined(__DARWIN__) */ + const char *t = ins; + u32 wc; + BOOL allocated; + ntfschar *outpos; + int shorts, ret = -1; + + shorts = utf8_to_utf16_size(ins); + if (shorts < 0) + goto fail; + + allocated = FALSE; + if (!*outs) { + *outs = ntfs_malloc((shorts + 1) * sizeof(ntfschar)); + if (!*outs) + goto fail; + allocated = TRUE; + } + + outpos = *outs; + + while(1) { + int m = utf8_to_unicode(&wc, t); + if (m <= 0) { + if (m < 0) { + /* do not leave space allocated if failed */ + if (allocated) { + free(*outs); + *outs = (ntfschar*)NULL; + } + goto fail; + } + *outpos++ = const_cpu_to_le16(0); + break; + } + if (wc < 0x10000) + *outpos++ = cpu_to_le16(wc); + else { + wc -= 0x10000; + *outpos++ = cpu_to_le16((wc >> 10) + 0xd800); + *outpos++ = cpu_to_le16((wc & 0x3ff) + 0xdc00); + } + t += m; + } + + ret = --outpos - *outs; +fail: +#if defined(__APPLE__) || defined(__DARWIN__) +#ifdef ENABLE_NFCONV + if(new_ins != NULL) + free(new_ins); +#endif /* ENABLE_NFCONV */ +#endif /* defined(__APPLE__) || defined(__DARWIN__) */ + return ret; +} + +/** + * ntfs_ucstombs - convert a little endian Unicode string to a multibyte string + * @ins: input Unicode string buffer + * @ins_len: length of input string in Unicode characters + * @outs: on return contains the (allocated) output multibyte string + * @outs_len: length of output buffer in bytes + * + * Convert the input little endian, 2-byte Unicode string @ins, of length + * @ins_len into the multibyte string format dictated by the current locale. + * + * If *@outs is NULL, the function allocates the string and the caller is + * responsible for calling free(*@outs); when finished with it. + * + * On success the function returns the number of bytes written to the output + * string *@outs (>= 0), not counting the terminating NULL byte. If the output + * string buffer was allocated, *@outs is set to it. + * + * On error, -1 is returned, and errno is set to the error code. The following + * error codes can be expected: + * EINVAL Invalid arguments (e.g. @ins or @outs is NULL). + * EILSEQ The input string cannot be represented as a multibyte + * sequence according to the current locale. + * ENAMETOOLONG Destination buffer is too small for input string. + * ENOMEM Not enough memory to allocate destination buffer. + */ +int ntfs_ucstombs(const ntfschar *ins, const int ins_len, char **outs, + int outs_len) +{ + char *mbs; + wchar_t wc; + int i, o, mbs_len; + int cnt = 0; +#ifdef HAVE_MBSINIT + mbstate_t mbstate; +#endif + + if (!ins || !outs) { + errno = EINVAL; + return -1; + } + mbs = *outs; + mbs_len = outs_len; + if (mbs && !mbs_len) { + errno = ENAMETOOLONG; + return -1; + } + if (use_utf8) + return ntfs_utf16_to_utf8(ins, ins_len, outs, outs_len); + if (!mbs) { + mbs_len = (ins_len + 1) * MB_CUR_MAX; + mbs = ntfs_malloc(mbs_len); + if (!mbs) + return -1; + } +#ifdef HAVE_MBSINIT + memset(&mbstate, 0, sizeof(mbstate)); +#else + wctomb(NULL, 0); +#endif + for (i = o = 0; i < ins_len; i++) { + /* Reallocate memory if necessary or abort. */ + if ((int)(o + MB_CUR_MAX) > mbs_len) { + char *tc; + if (mbs == *outs) { + errno = ENAMETOOLONG; + return -1; + } + tc = ntfs_malloc((mbs_len + 64) & ~63); + if (!tc) + goto err_out; + memcpy(tc, mbs, mbs_len); + mbs_len = (mbs_len + 64) & ~63; + free(mbs); + mbs = tc; + } + /* Convert the LE Unicode character to a CPU wide character. */ + wc = (wchar_t)le16_to_cpu(ins[i]); + if (!wc) + break; + /* Convert the CPU endian wide character to multibyte. */ +#ifdef HAVE_MBSINIT + cnt = wcrtomb(mbs + o, wc, &mbstate); +#else + cnt = wctomb(mbs + o, wc); +#endif + if (cnt == -1) + goto err_out; + if (cnt <= 0) { + ntfs_log_debug("Eeek. cnt <= 0, cnt = %i\n", cnt); + errno = EINVAL; + goto err_out; + } + o += cnt; + } +#ifdef HAVE_MBSINIT + /* Make sure we are back in the initial state. */ + if (!mbsinit(&mbstate)) { + ntfs_log_debug("Eeek. mbstate not in initial state!\n"); + errno = EILSEQ; + goto err_out; + } +#endif + /* Now write the NULL character. */ + mbs[o] = '\0'; + if (*outs != mbs) + *outs = mbs; + return o; +err_out: + if (mbs != *outs) { + int eo = errno; + free(mbs); + errno = eo; + } + return -1; +} + +/** + * ntfs_mbstoucs - convert a multibyte string to a little endian Unicode string + * @ins: input multibyte string buffer + * @outs: on return contains the (allocated) output Unicode string + * + * Convert the input multibyte string @ins, from the current locale into the + * corresponding little endian, 2-byte Unicode string. + * + * The function allocates the string and the caller is responsible for calling + * free(*@outs); when finished with it. + * + * On success the function returns the number of Unicode characters written to + * the output string *@outs (>= 0), not counting the terminating Unicode NULL + * character. + * + * On error, -1 is returned, and errno is set to the error code. The following + * error codes can be expected: + * EINVAL Invalid arguments (e.g. @ins or @outs is NULL). + * EILSEQ The input string cannot be represented as a Unicode + * string according to the current locale. + * ENAMETOOLONG Destination buffer is too small for input string. + * ENOMEM Not enough memory to allocate destination buffer. + */ +int ntfs_mbstoucs(const char *ins, ntfschar **outs) +{ + ntfschar *ucs; + const char *s; + wchar_t wc; + int i, o, cnt, ins_len, ucs_len, ins_size; +#ifdef HAVE_MBSINIT + mbstate_t mbstate; +#endif + + if (!ins || !outs) { + errno = EINVAL; + return -1; + } + + if (use_utf8) + return ntfs_utf8_to_utf16(ins, outs); + + /* Determine the size of the multi-byte string in bytes. */ + ins_size = strlen(ins); + /* Determine the length of the multi-byte string. */ + s = ins; +#if defined(HAVE_MBSINIT) + memset(&mbstate, 0, sizeof(mbstate)); + ins_len = mbsrtowcs(NULL, (const char **)&s, 0, &mbstate); +#ifdef __CYGWIN32__ + if (!ins_len && *ins) { + /* Older Cygwin had broken mbsrtowcs() implementation. */ + ins_len = strlen(ins); + } +#endif +#elif !defined(DJGPP) + ins_len = mbstowcs(NULL, s, 0); +#else + /* Eeek!!! DJGPP has broken mbstowcs() implementation!!! */ + ins_len = strlen(ins); +#endif + if (ins_len == -1) + return ins_len; +#ifdef HAVE_MBSINIT + if ((s != ins) || !mbsinit(&mbstate)) { +#else + if (s != ins) { +#endif + errno = EILSEQ; + return -1; + } + /* Add the NULL terminator. */ + ins_len++; + ucs_len = ins_len; + ucs = ntfs_malloc(ucs_len * sizeof(ntfschar)); + if (!ucs) + return -1; +#ifdef HAVE_MBSINIT + memset(&mbstate, 0, sizeof(mbstate)); +#else + mbtowc(NULL, NULL, 0); +#endif + for (i = o = cnt = 0; i < ins_size; i += cnt, o++) { + /* Reallocate memory if necessary. */ + if (o >= ucs_len) { + ntfschar *tc; + ucs_len = (ucs_len * sizeof(ntfschar) + 64) & ~63; + tc = realloc(ucs, ucs_len); + if (!tc) + goto err_out; + ucs = tc; + ucs_len /= sizeof(ntfschar); + } + /* Convert the multibyte character to a wide character. */ +#ifdef HAVE_MBSINIT + cnt = mbrtowc(&wc, ins + i, ins_size - i, &mbstate); +#else + cnt = mbtowc(&wc, ins + i, ins_size - i); +#endif + if (!cnt) + break; + if (cnt == -1) + goto err_out; + if (cnt < -1) { + ntfs_log_trace("Eeek. cnt = %i\n", cnt); + errno = EINVAL; + goto err_out; + } + /* Make sure we are not overflowing the NTFS Unicode set. */ + if ((unsigned long)wc >= (unsigned long)(1 << + (8 * sizeof(ntfschar)))) { + errno = EILSEQ; + goto err_out; + } + /* Convert the CPU wide character to a LE Unicode character. */ + ucs[o] = cpu_to_le16(wc); + } +#ifdef HAVE_MBSINIT + /* Make sure we are back in the initial state. */ + if (!mbsinit(&mbstate)) { + ntfs_log_trace("Eeek. mbstate not in initial state!\n"); + errno = EILSEQ; + goto err_out; + } +#endif + /* Now write the NULL character. */ + ucs[o] = cpu_to_le16(L'\0'); + *outs = ucs; + return o; +err_out: + free(ucs); + return -1; +} + +/** + * ntfs_upcase_table_build - build the default upcase table for NTFS + * @uc: destination buffer where to store the built table + * @uc_len: size of destination buffer in bytes + * + * ntfs_upcase_table_build() builds the default upcase table for NTFS and + * stores it in the caller supplied buffer @uc of size @uc_len. + * + * Note, @uc_len must be at least 128kiB in size or bad things will happen! + */ +void ntfs_upcase_table_build(ntfschar *uc, u32 uc_len) +{ + static int uc_run_table[][3] = { /* Start, End, Add */ + {0x0061, 0x007B, -32}, {0x0451, 0x045D, -80}, {0x1F70, 0x1F72, 74}, + {0x00E0, 0x00F7, -32}, {0x045E, 0x0460, -80}, {0x1F72, 0x1F76, 86}, + {0x00F8, 0x00FF, -32}, {0x0561, 0x0587, -48}, {0x1F76, 0x1F78, 100}, + {0x0256, 0x0258, -205}, {0x1F00, 0x1F08, 8}, {0x1F78, 0x1F7A, 128}, + {0x028A, 0x028C, -217}, {0x1F10, 0x1F16, 8}, {0x1F7A, 0x1F7C, 112}, + {0x03AC, 0x03AD, -38}, {0x1F20, 0x1F28, 8}, {0x1F7C, 0x1F7E, 126}, + {0x03AD, 0x03B0, -37}, {0x1F30, 0x1F38, 8}, {0x1FB0, 0x1FB2, 8}, + {0x03B1, 0x03C2, -32}, {0x1F40, 0x1F46, 8}, {0x1FD0, 0x1FD2, 8}, + {0x03C2, 0x03C3, -31}, {0x1F51, 0x1F52, 8}, {0x1FE0, 0x1FE2, 8}, + {0x03C3, 0x03CC, -32}, {0x1F53, 0x1F54, 8}, {0x1FE5, 0x1FE6, 7}, + {0x03CC, 0x03CD, -64}, {0x1F55, 0x1F56, 8}, {0x2170, 0x2180, -16}, + {0x03CD, 0x03CF, -63}, {0x1F57, 0x1F58, 8}, {0x24D0, 0x24EA, -26}, + {0x0430, 0x0450, -32}, {0x1F60, 0x1F68, 8}, {0xFF41, 0xFF5B, -32}, + {0} + }; + static int uc_dup_table[][2] = { /* Start, End */ + {0x0100, 0x012F}, {0x01A0, 0x01A6}, {0x03E2, 0x03EF}, {0x04CB, 0x04CC}, + {0x0132, 0x0137}, {0x01B3, 0x01B7}, {0x0460, 0x0481}, {0x04D0, 0x04EB}, + {0x0139, 0x0149}, {0x01CD, 0x01DD}, {0x0490, 0x04BF}, {0x04EE, 0x04F5}, + {0x014A, 0x0178}, {0x01DE, 0x01EF}, {0x04BF, 0x04BF}, {0x04F8, 0x04F9}, + {0x0179, 0x017E}, {0x01F4, 0x01F5}, {0x04C1, 0x04C4}, {0x1E00, 0x1E95}, + {0x018B, 0x018B}, {0x01FA, 0x0218}, {0x04C7, 0x04C8}, {0x1EA0, 0x1EF9}, + {0} + }; + static int uc_byte_table[][2] = { /* Offset, Value */ + {0x00FF, 0x0178}, {0x01AD, 0x01AC}, {0x01F3, 0x01F1}, {0x0269, 0x0196}, + {0x0183, 0x0182}, {0x01B0, 0x01AF}, {0x0253, 0x0181}, {0x026F, 0x019C}, + {0x0185, 0x0184}, {0x01B9, 0x01B8}, {0x0254, 0x0186}, {0x0272, 0x019D}, + {0x0188, 0x0187}, {0x01BD, 0x01BC}, {0x0259, 0x018F}, {0x0275, 0x019F}, + {0x018C, 0x018B}, {0x01C6, 0x01C4}, {0x025B, 0x0190}, {0x0283, 0x01A9}, + {0x0192, 0x0191}, {0x01C9, 0x01C7}, {0x0260, 0x0193}, {0x0288, 0x01AE}, + {0x0199, 0x0198}, {0x01CC, 0x01CA}, {0x0263, 0x0194}, {0x0292, 0x01B7}, + {0x01A8, 0x01A7}, {0x01DD, 0x018E}, {0x0268, 0x0197}, + {0} + }; + int i, r; + int k, off; + + memset((char*)uc, 0, uc_len); + uc_len >>= 1; + if (uc_len > 65536) + uc_len = 65536; + for (i = 0; (u32)i < uc_len; i++) + uc[i] = cpu_to_le16(i); + for (r = 0; uc_run_table[r][0]; r++) { + off = uc_run_table[r][2]; + for (i = uc_run_table[r][0]; i < uc_run_table[r][1]; i++) + uc[i] = cpu_to_le16(i + off); + } + for (r = 0; uc_dup_table[r][0]; r++) + for (i = uc_dup_table[r][0]; i < uc_dup_table[r][1]; i += 2) + uc[i + 1] = cpu_to_le16(i); + for (r = 0; uc_byte_table[r][0]; r++) { + k = uc_byte_table[r][1]; + uc[uc_byte_table[r][0]] = cpu_to_le16(k); + } +} + +/** + * ntfs_str2ucs - convert a string to a valid NTFS file name + * @s: input string + * @len: length of output buffer in Unicode characters + * + * Convert the input @s string into the corresponding little endian, + * 2-byte Unicode string. The length of the converted string is less + * or equal to the maximum length allowed by the NTFS format (255). + * + * If @s is NULL then return AT_UNNAMED. + * + * On success the function returns the Unicode string in an allocated + * buffer and the caller is responsible to free it when it's not needed + * anymore. + * + * On error NULL is returned and errno is set to the error code. + */ +ntfschar *ntfs_str2ucs(const char *s, int *len) +{ + ntfschar *ucs = NULL; + + if (s && ((*len = ntfs_mbstoucs(s, &ucs)) == -1)) { + ntfs_log_perror("Couldn't convert '%s' to Unicode", s); + return NULL; + } + if (*len > NTFS_MAX_NAME_LEN) { + free(ucs); + errno = ENAMETOOLONG; + return NULL; + } + if (!ucs || !*len) { + ucs = AT_UNNAMED; + *len = 0; + } + return ucs; +} + +/** + * ntfs_ucsfree - free memory allocated by ntfs_str2ucs() + * @ucs input string to be freed + * + * Free memory at @ucs and which was allocated by ntfs_str2ucs. + * + * Return value: none. + */ +void ntfs_ucsfree(ntfschar *ucs) +{ + if (ucs && (ucs != AT_UNNAMED)) + free(ucs); +} + +/* + * Check whether a name contains no chars forbidden + * for DOS or Win32 use + * + * If there is a bad char, errno is set to EINVAL + */ + +BOOL ntfs_forbidden_chars(const ntfschar *name, int len) +{ + BOOL forbidden; + int ch; + int i; + u32 mainset = (1L << ('\"' - 0x20)) + | (1L << ('*' - 0x20)) + | (1L << ('/' - 0x20)) + | (1L << (':' - 0x20)) + | (1L << ('<' - 0x20)) + | (1L << ('>' - 0x20)) + | (1L << ('?' - 0x20)); + + forbidden = (len == 0) || (le16_to_cpu(name[len-1]) == ' '); + for (i=0; i= vol->upcase_len) + || ((shortname[i] != longname[i]) + && (shortname[i] != vol->upcase[ch]))) + collapsible = FALSE; + } + return (collapsible); +} + +/* + * Define the character encoding to be used. + * Use UTF-8 unless specified otherwise. + */ + +int ntfs_set_char_encoding(const char *locale) +{ + use_utf8 = 0; + if (!locale || strstr(locale,"utf8") || strstr(locale,"UTF8") + || strstr(locale,"utf-8") || strstr(locale,"UTF-8")) + use_utf8 = 1; + else + if (setlocale(LC_ALL, locale)) + use_utf8 = 0; + else { + ntfs_log_error("Invalid locale, encoding to UTF-8\n"); + use_utf8 = 1; + } + return 0; /* always successful */ +} + +#if defined(__APPLE__) || defined(__DARWIN__) + +int ntfs_macosx_normalize_filenames(int normalize) { +#ifdef ENABLE_NFCONV + if(normalize == 0 || normalize == 1) { + nfconvert_utf8 = normalize; + return 0; + } + else + return -1; +#else + return -1; +#endif /* ENABLE_NFCONV */ +} + +int ntfs_macosx_normalize_utf8(const char *utf8_string, char **target, + int composed) { +#ifdef ENABLE_NFCONV + /* For this code to compile, the CoreFoundation framework must be fed to the linker. */ + CFStringRef cfSourceString; + CFMutableStringRef cfMutableString; + CFRange rangeToProcess; + CFIndex requiredBufferLength; + char *result = NULL; + int resultLength = -1; + + /* Convert the UTF-8 string to a CFString. */ + cfSourceString = CFStringCreateWithCString(kCFAllocatorDefault, utf8_string, kCFStringEncodingUTF8); + if(cfSourceString == NULL) { + ntfs_log_error("CFStringCreateWithCString failed!\n"); + return -2; + } + + /* Create a mutable string from cfSourceString that we are free to modify. */ + cfMutableString = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, cfSourceString); + CFRelease(cfSourceString); /* End-of-life. */ + if(cfMutableString == NULL) { + ntfs_log_error("CFStringCreateMutableCopy failed!\n"); + return -3; + } + + /* Normalize the mutable string to the desired normalization form. */ + CFStringNormalize(cfMutableString, (composed != 0 ? kCFStringNormalizationFormC : kCFStringNormalizationFormD)); + + /* Store the resulting string in a '\0'-terminated UTF-8 encoded char* buffer. */ + rangeToProcess = CFRangeMake(0, CFStringGetLength(cfMutableString)); + if(CFStringGetBytes(cfMutableString, rangeToProcess, kCFStringEncodingUTF8, 0, false, NULL, 0, &requiredBufferLength) > 0) { + resultLength = sizeof(char)*(requiredBufferLength + 1); + result = ntfs_calloc(resultLength); + + if(result != NULL) { + if(CFStringGetBytes(cfMutableString, rangeToProcess, kCFStringEncodingUTF8, + 0, false, (UInt8*)result, resultLength-1, &requiredBufferLength) <= 0) { + ntfs_log_error("Could not perform UTF-8 conversion of normalized CFMutableString.\n"); + free(result); + result = NULL; + } + } + else + ntfs_log_error("Could not perform a ntfs_calloc of %d bytes for char *result.\n", resultLength); + } + else + ntfs_log_error("Could not perform check for required length of UTF-8 conversion of normalized CFMutableString.\n"); + + + CFRelease(cfMutableString); + + if(result != NULL) { + *target = result; + return resultLength - 1; + } + else + return -1; +#else + return -1; +#endif /* ENABLE_NFCONV */ +} +#endif /* defined(__APPLE__) || defined(__DARWIN__) */ diff --git a/libntfs-3g/unix_io.c b/libntfs-3g/unix_io.c new file mode 100755 index 0000000..53850d1 --- a/dev/null +++ b/libntfs-3g/unix_io.c @@ -0,0 +1,386 @@ +/** + * unix_io.c - Unix style disk io functions. Originated from the Linux-NTFS project. + * + * Copyright (c) 2000-2006 Anton Altaparmakov + * + * This program/include file 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/include file 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 (in the main directory of the NTFS-3G + * distribution in the file COPYING); if not, write to the Free Software + * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_ERRNO_H +#include +#endif +#ifdef HAVE_STDIO_H +#include +#endif +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_STAT_H +#include +#endif +#ifdef HAVE_FCNTL_H +#include +#endif +#ifdef HAVE_SYS_IOCTL_H +#include +#endif +#ifdef HAVE_LINUX_FD_H +#include +#endif + +#include "types.h" +#include "mst.h" +#include "debug.h" +#include "device.h" +#include "logging.h" +#include "misc.h" + + + +#ifdef __USE_FILE_OFFSET64 +#include +#define lseek lseek64 +#define pread __pread64 +#define pwrite __pwrite64 +#define fcntl __fcntl64 +#endif + + +#define DEV_FD(dev) (*(int *)dev->d_private) + +/* Define to nothing if not present on this system. */ +#ifndef O_EXCL +# define O_EXCL 0 +#endif + +/** + * fsync replacement which makes every effort to try to get the data down to + * disk, using different means for different operating systems. Specifically, + * it issues the proper fcntl for Mac OS X or does fsync where it is available + * or as a last resort calls the fsync function. Information on this problem + * was retrieved from: + * http://mirror.linux.org.au/pub/linux.conf.au/2007/video/talks/278.pdf + */ +static int ntfs_fsync(int fildes) +{ + int ret = -1; +#if defined(__APPLE__) || defined(__DARWIN__) +# ifndef F_FULLFSYNC +# error "Mac OS X: F_FULLFSYNC is not defined. Either you didn't include fcntl.h or you're using an older, unsupported version of Mac OS X (pre-10.3)." +# endif + /* + * Apple has disabled fsync() for internal disk drives in OS X. + * To force a synchronization of disk contents, we use a Mac OS X + * specific fcntl, F_FULLFSYNC. + */ + ret = fcntl(fildes, F_FULLFSYNC, NULL); + if (ret) { + /* + * If we are not on a file system that supports this, + * then fall back to a plain fsync. + */ + ret = fsync(fildes); + } +#else + ret = fsync(fildes); +#endif + return ret; +} + +/** + * ntfs_device_unix_io_open - Open a device and lock it exclusively + * @dev: + * @flags: + * + * Description... + * + * Returns: + */ +static int ntfs_device_unix_io_open(struct ntfs_device *dev, int flags) +{ + struct flock flk; + struct stat sbuf; + int err; + + if (NDevOpen(dev)) { + errno = EBUSY; + return -1; + } + if (stat(dev->d_name, &sbuf)) { + ntfs_log_perror("Failed to access '%s'", dev->d_name); + return -1; + } + if (S_ISBLK(sbuf.st_mode)) + NDevSetBlock(dev); + + dev->d_private = ntfs_malloc(sizeof(int)); + if (!dev->d_private) + return -1; + /* + * Open file for exclusive access if mounting r/w. + * Fuseblk takes care about block devices. + */ + if (!NDevBlock(dev) && (flags & O_RDWR) == O_RDWR) + flags |= O_EXCL; + *(int*)dev->d_private = open(dev->d_name, flags); + if (*(int*)dev->d_private == -1) { + err = errno; + goto err_out; + } + + if ((flags & O_RDWR) != O_RDWR) + NDevSetReadOnly(dev); + + memset(&flk, 0, sizeof(flk)); + if (NDevReadOnly(dev)) + flk.l_type = F_RDLCK; + else + flk.l_type = F_WRLCK; + flk.l_whence = SEEK_SET; + flk.l_start = flk.l_len = 0LL; + if (fcntl(DEV_FD(dev), F_SETLK, &flk)) { + err = errno; + ntfs_log_perror("Failed to %s lock '%s'", NDevReadOnly(dev) ? + "read" : "write", dev->d_name); + if (close(DEV_FD(dev))) + ntfs_log_perror("Failed to close '%s'", dev->d_name); + goto err_out; + } + + NDevSetOpen(dev); + return 0; +err_out: + free(dev->d_private); + dev->d_private = NULL; + errno = err; + return -1; +} + +/** + * ntfs_device_unix_io_close - Close the device, releasing the lock + * @dev: + * + * Description... + * + * Returns: + */ +static int ntfs_device_unix_io_close(struct ntfs_device *dev) +{ + struct flock flk; + + if (!NDevOpen(dev)) { + errno = EBADF; + ntfs_log_perror("Device %s is not open", dev->d_name); + return -1; + } + if (NDevDirty(dev)) + if (ntfs_fsync(DEV_FD(dev))) { + ntfs_log_perror("Failed to fsync device %s", dev->d_name); + return -1; + } + + memset(&flk, 0, sizeof(flk)); + flk.l_type = F_UNLCK; + flk.l_whence = SEEK_SET; + flk.l_start = flk.l_len = 0LL; + if (fcntl(DEV_FD(dev), F_SETLK, &flk)) + ntfs_log_perror("Could not unlock %s", dev->d_name); + if (close(DEV_FD(dev))) { + ntfs_log_perror("Failed to close device %s", dev->d_name); + return -1; + } + NDevClearOpen(dev); + free(dev->d_private); + dev->d_private = NULL; + return 0; +} + +/** + * ntfs_device_unix_io_seek - Seek to a place on the device + * @dev: + * @offset: + * @whence: + * + * Description... + * + * Returns: + */ +static s64 ntfs_device_unix_io_seek(struct ntfs_device *dev, s64 offset, + int whence) +{ + return lseek(DEV_FD(dev), offset, whence); +} + +/** + * ntfs_device_unix_io_read - Read from the device, from the current location + * @dev: + * @buf: + * @count: + * + * Description... + * + * Returns: + */ +static s64 ntfs_device_unix_io_read(struct ntfs_device *dev, void *buf, + s64 count) +{ + return read(DEV_FD(dev), buf, count); +} + +/** + * ntfs_device_unix_io_write - Write to the device, at the current location + * @dev: + * @buf: + * @count: + * + * Description... + * + * Returns: + */ +static s64 ntfs_device_unix_io_write(struct ntfs_device *dev, const void *buf, + s64 count) +{ + if (NDevReadOnly(dev)) { + errno = EROFS; + return -1; + } + NDevSetDirty(dev); + return write(DEV_FD(dev), buf, count); +} + +/** + * ntfs_device_unix_io_pread - Perform a positioned read from the device + * @dev: + * @buf: + * @count: + * @offset: + * + * Description... + * + * Returns: + */ +static s64 ntfs_device_unix_io_pread(struct ntfs_device *dev, void *buf, + s64 count, s64 offset) +{ + return pread(DEV_FD(dev), buf, count, offset); +} + +/** + * ntfs_device_unix_io_pwrite - Perform a positioned write to the device + * @dev: + * @buf: + * @count: + * @offset: + * + * Description... + * + * Returns: + */ +static s64 ntfs_device_unix_io_pwrite(struct ntfs_device *dev, const void *buf, + s64 count, s64 offset) +{ + if (NDevReadOnly(dev)) { + errno = EROFS; + return -1; + } + NDevSetDirty(dev); + return pwrite(DEV_FD(dev), buf, count, offset); +} + +/** + * ntfs_device_unix_io_sync - Flush any buffered changes to the device + * @dev: + * + * Description... + * + * Returns: + */ +static int ntfs_device_unix_io_sync(struct ntfs_device *dev) +{ + int res = 0; + + if (!NDevReadOnly(dev)) { + res = ntfs_fsync(DEV_FD(dev)); + if (res) + ntfs_log_perror("Failed to sync device %s", dev->d_name); + else + NDevClearDirty(dev); + } + return res; +} + +/** + * ntfs_device_unix_io_stat - Get information about the device + * @dev: + * @buf: + * + * Description... + * + * Returns: + */ +static int ntfs_device_unix_io_stat(struct ntfs_device *dev, struct stat *buf) +{ + return fstat(DEV_FD(dev), buf); +} + +/** + * ntfs_device_unix_io_ioctl - Perform an ioctl on the device + * @dev: + * @request: + * @argp: + * + * Description... + * + * Returns: + */ +static int ntfs_device_unix_io_ioctl(struct ntfs_device *dev, int request, + void *argp) +{ + return ioctl(DEV_FD(dev), request, argp); +} + +#ifdef __USE_FILE_OFFSET64 +#define pread pread +#define pwrite pwrite +#endif +/** + * Device operations for working with unix style devices and files. + */ +struct ntfs_device_operations ntfs_device_unix_io_ops = { + .open = ntfs_device_unix_io_open, + .close = ntfs_device_unix_io_close, + .seek = ntfs_device_unix_io_seek, + .read = ntfs_device_unix_io_read, + .write = ntfs_device_unix_io_write, + .pread = ntfs_device_unix_io_pread, + .pwrite = ntfs_device_unix_io_pwrite, + .sync = ntfs_device_unix_io_sync, + .stat = ntfs_device_unix_io_stat, + .ioctl = ntfs_device_unix_io_ioctl, +}; diff --git a/libntfs-3g/volume.c b/libntfs-3g/volume.c new file mode 100755 index 0000000..ecacb18 --- a/dev/null +++ b/libntfs-3g/volume.c @@ -0,0 +1,1663 @@ +/** + * volume.c - NTFS volume handling code. Originated from the Linux-NTFS project. + * + * Copyright (c) 2000-2006 Anton Altaparmakov + * Copyright (c) 2002-2009 Szabolcs Szakacsits + * Copyright (c) 2004-2005 Richard Russon + * Copyright (c) 2010 Jean-Pierre Andre + * + * This program/include file 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/include file 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 (in the main directory of the NTFS-3G + * distribution in the file COPYING); if not, write to the Free Software + * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STDIO_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_FCNTL_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_ERRNO_H +#include +#endif +#ifdef HAVE_SYS_STAT_H +#include +#endif +#ifdef HAVE_LIMITS_H +#include +#endif +#ifdef HAVE_LOCALE_H +#include +#endif + +#include "compat.h" +#include "volume.h" +#include "attrib.h" +#include "mft.h" +#include "bootsect.h" +#include "device.h" +#include "debug.h" +#include "inode.h" +#include "runlist.h" +#include "logfile.h" +#include "dir.h" +#include "logging.h" +#include "cache.h" +#include "misc.h" + +const char *ntfs_home = +"Ntfs-3g news, support and information: http://ntfs-3g.org\n"; + +static const char *invalid_ntfs_msg = +"The device '%s' doesn't seem to have a valid NTFS.\n" +"Maybe the wrong device is used? Or the whole disk instead of a\n" +"partition (e.g. /dev/sda, not /dev/sda1)? Or the other way around?\n"; + +static const char *corrupt_volume_msg = +"NTFS is either inconsistent, or there is a hardware fault, or it's a\n" +"SoftRAID/FakeRAID hardware. In the first case run chkdsk /f on Windows\n" +"then reboot into Windows twice. The usage of the /f parameter is very\n" +"important! If the device is a SoftRAID/FakeRAID then first activate\n" +"it and mount a different device under the /dev/mapper/ directory, (e.g.\n" +"/dev/mapper/nvidia_eahaabcc1). Please see the 'dmraid' documentation\n" +"for more details.\n"; + +static const char *hibernated_volume_msg = +"The NTFS partition is hibernated. Please resume and shutdown Windows\n" +"properly, or mount the volume read-only with the 'ro' mount option, or\n" +"mount the volume read-write with the 'remove_hiberfile' mount option.\n" +"For example type on the command line:\n" +"\n" +" mount -t ntfs-3g -o remove_hiberfile %s %s\n" +"\n"; + +static const char *unclean_journal_msg = +"Write access is denied because the disk wasn't safely powered\n" +"off and the 'norecover' mount option was specified.\n"; + +static const char *opened_volume_msg = +"Mount is denied because the NTFS volume is already exclusively opened.\n" +"The volume may be already mounted, or another software may use it which\n" +"could be identified for example by the help of the 'fuser' command.\n"; + +static const char *fakeraid_msg = +"Either the device is missing or it's powered down, or you have\n" +"SoftRAID hardware and must use an activated, different device under\n" +"/dev/mapper/, (e.g. /dev/mapper/nvidia_eahaabcc1) to mount NTFS.\n" +"Please see the 'dmraid' documentation for help.\n"; + +static const char *access_denied_msg = +"Please check '%s' and the ntfs-3g binary permissions,\n" +"and the mounting user ID. More explanation is provided at\n" +"http://ntfs-3g.org/support.html#unprivileged\n"; + +/** + * ntfs_volume_alloc - Create an NTFS volume object and initialise it + * + * Description... + * + * Returns: + */ +ntfs_volume *ntfs_volume_alloc(void) +{ + return ntfs_calloc(sizeof(ntfs_volume)); +} + +static void ntfs_attr_free(ntfs_attr **na) +{ + if (na && *na) { + ntfs_attr_close(*na); + *na = NULL; + } +} + +static int ntfs_inode_free(ntfs_inode **ni) +{ + int ret = -1; + + if (ni && *ni) { + ret = ntfs_inode_close(*ni); + *ni = NULL; + } + + return ret; +} + +static void ntfs_error_set(int *err) +{ + if (!*err) + *err = errno; +} + +/** + * __ntfs_volume_release - Destroy an NTFS volume object + * @v: + * + * Description... + * + * Returns: + */ +static int __ntfs_volume_release(ntfs_volume *v) +{ + int err = 0; + + if (ntfs_inode_free(&v->vol_ni)) + ntfs_error_set(&err); + /* + * FIXME: Inodes must be synced before closing + * attributes, otherwise unmount could fail. + */ + if (v->lcnbmp_ni && NInoDirty(v->lcnbmp_ni)) + ntfs_inode_sync(v->lcnbmp_ni); + ntfs_attr_free(&v->lcnbmp_na); + if (ntfs_inode_free(&v->lcnbmp_ni)) + ntfs_error_set(&err); + + if (v->mft_ni && NInoDirty(v->mft_ni)) + ntfs_inode_sync(v->mft_ni); + ntfs_attr_free(&v->mftbmp_na); + ntfs_attr_free(&v->mft_na); + if (ntfs_inode_free(&v->mft_ni)) + ntfs_error_set(&err); + + if (v->mftmirr_ni && NInoDirty(v->mftmirr_ni)) + ntfs_inode_sync(v->mftmirr_ni); + ntfs_attr_free(&v->mftmirr_na); + if (ntfs_inode_free(&v->mftmirr_ni)) + ntfs_error_set(&err); + + if (v->dev) { + struct ntfs_device *dev = v->dev; + + if (dev->d_ops->sync(dev)) + ntfs_error_set(&err); + if (dev->d_ops->close(dev)) + ntfs_error_set(&err); + } + + ntfs_free_lru_caches(v); + free(v->vol_name); + free(v->upcase); + free(v->attrdef); + free(v); + + errno = err; + return errno ? -1 : 0; +} + +static void ntfs_attr_setup_flag(ntfs_inode *ni) +{ + STANDARD_INFORMATION *si; + + si = ntfs_attr_readall(ni, AT_STANDARD_INFORMATION, AT_UNNAMED, 0, NULL); + if (si) { + ni->flags = si->file_attributes; + free(si); + } +} + +/** + * ntfs_mft_load - load the $MFT and setup the ntfs volume with it + * @vol: ntfs volume whose $MFT to load + * + * Load $MFT from @vol and setup @vol with it. After calling this function the + * volume @vol is ready for use by all read access functions provided by the + * ntfs library. + * + * Return 0 on success and -1 on error with errno set to the error code. + */ +static int ntfs_mft_load(ntfs_volume *vol) +{ + VCN next_vcn, last_vcn, highest_vcn; + s64 l; + MFT_RECORD *mb = NULL; + ntfs_attr_search_ctx *ctx = NULL; + ATTR_RECORD *a; + int eo; + + /* Manually setup an ntfs_inode. */ + vol->mft_ni = ntfs_inode_allocate(vol); + mb = ntfs_malloc(vol->mft_record_size); + if (!vol->mft_ni || !mb) { + ntfs_log_perror("Error allocating memory for $MFT"); + goto error_exit; + } + vol->mft_ni->mft_no = 0; + vol->mft_ni->mrec = mb; + /* Can't use any of the higher level functions yet! */ + l = ntfs_mst_pread(vol->dev, vol->mft_lcn << vol->cluster_size_bits, 1, + vol->mft_record_size, mb); + if (l != 1) { + if (l != -1) + errno = EIO; + ntfs_log_perror("Error reading $MFT"); + goto error_exit; + } + + if (ntfs_mft_record_check(vol, 0, mb)) + goto error_exit; + + ctx = ntfs_attr_get_search_ctx(vol->mft_ni, NULL); + if (!ctx) + goto error_exit; + + /* Find the $ATTRIBUTE_LIST attribute in $MFT if present. */ + if (ntfs_attr_lookup(AT_ATTRIBUTE_LIST, AT_UNNAMED, 0, 0, 0, NULL, 0, + ctx)) { + if (errno != ENOENT) { + ntfs_log_error("$MFT has corrupt attribute list.\n"); + goto io_error_exit; + } + goto mft_has_no_attr_list; + } + NInoSetAttrList(vol->mft_ni); + l = ntfs_get_attribute_value_length(ctx->attr); + if (l <= 0 || l > 0x40000) { + ntfs_log_error("$MFT/$ATTR_LIST invalid length (%lld).\n", + (long long)l); + goto io_error_exit; + } + vol->mft_ni->attr_list_size = l; + vol->mft_ni->attr_list = ntfs_malloc(l); + if (!vol->mft_ni->attr_list) + goto error_exit; + + l = ntfs_get_attribute_value(vol, ctx->attr, vol->mft_ni->attr_list); + if (!l) { + ntfs_log_error("Failed to get value of $MFT/$ATTR_LIST.\n"); + goto io_error_exit; + } + if (l != vol->mft_ni->attr_list_size) { + ntfs_log_error("Partial read of $MFT/$ATTR_LIST (%lld != " + "%u).\n", (long long)l, + vol->mft_ni->attr_list_size); + goto io_error_exit; + } + +mft_has_no_attr_list: + + ntfs_attr_setup_flag(vol->mft_ni); + + /* We now have a fully setup ntfs inode for $MFT in vol->mft_ni. */ + + /* Get an ntfs attribute for $MFT/$DATA and set it up, too. */ + vol->mft_na = ntfs_attr_open(vol->mft_ni, AT_DATA, AT_UNNAMED, 0); + if (!vol->mft_na) { + ntfs_log_perror("Failed to open ntfs attribute"); + goto error_exit; + } + /* Read all extents from the $DATA attribute in $MFT. */ + ntfs_attr_reinit_search_ctx(ctx); + last_vcn = vol->mft_na->allocated_size >> vol->cluster_size_bits; + highest_vcn = next_vcn = 0; + a = NULL; + while (!ntfs_attr_lookup(AT_DATA, AT_UNNAMED, 0, 0, next_vcn, NULL, 0, + ctx)) { + runlist_element *nrl; + + a = ctx->attr; + /* $MFT must be non-resident. */ + if (!a->non_resident) { + ntfs_log_error("$MFT must be non-resident.\n"); + goto io_error_exit; + } + /* $MFT must be uncompressed and unencrypted. */ + if (a->flags & ATTR_COMPRESSION_MASK || + a->flags & ATTR_IS_ENCRYPTED) { + ntfs_log_error("$MFT must be uncompressed and " + "unencrypted.\n"); + goto io_error_exit; + } + /* + * Decompress the mapping pairs array of this extent and merge + * the result into the existing runlist. No need for locking + * as we have exclusive access to the inode at this time and we + * are a mount in progress task, too. + */ + nrl = ntfs_mapping_pairs_decompress(vol, a, vol->mft_na->rl); + if (!nrl) { + ntfs_log_perror("ntfs_mapping_pairs_decompress() failed"); + goto error_exit; + } + vol->mft_na->rl = nrl; + + /* Get the lowest vcn for the next extent. */ + highest_vcn = sle64_to_cpu(a->highest_vcn); + next_vcn = highest_vcn + 1; + + /* Only one extent or error, which we catch below. */ + if (next_vcn <= 0) + break; + + /* Avoid endless loops due to corruption. */ + if (next_vcn < sle64_to_cpu(a->lowest_vcn)) { + ntfs_log_error("$MFT has corrupt attribute list.\n"); + goto io_error_exit; + } + } + if (!a) { + ntfs_log_error("$MFT/$DATA attribute not found.\n"); + goto io_error_exit; + } + if (highest_vcn && highest_vcn != last_vcn - 1) { + ntfs_log_error("Failed to load runlist for $MFT/$DATA.\n"); + ntfs_log_error("highest_vcn = 0x%llx, last_vcn - 1 = 0x%llx\n", + (long long)highest_vcn, (long long)last_vcn - 1); + goto io_error_exit; + } + /* Done with the $Mft mft record. */ + ntfs_attr_put_search_ctx(ctx); + ctx = NULL; + /* + * The volume is now setup so we can use all read access functions. + */ + vol->mftbmp_na = ntfs_attr_open(vol->mft_ni, AT_BITMAP, AT_UNNAMED, 0); + if (!vol->mftbmp_na) { + ntfs_log_perror("Failed to open $MFT/$BITMAP"); + goto error_exit; + } + return 0; +io_error_exit: + errno = EIO; +error_exit: + eo = errno; + if (ctx) + ntfs_attr_put_search_ctx(ctx); + if (vol->mft_na) { + ntfs_attr_close(vol->mft_na); + vol->mft_na = NULL; + } + if (vol->mft_ni) { + ntfs_inode_close(vol->mft_ni); + vol->mft_ni = NULL; + } + errno = eo; + return -1; +} + +/** + * ntfs_mftmirr_load - load the $MFTMirr and setup the ntfs volume with it + * @vol: ntfs volume whose $MFTMirr to load + * + * Load $MFTMirr from @vol and setup @vol with it. After calling this function + * the volume @vol is ready for use by all write access functions provided by + * the ntfs library (assuming ntfs_mft_load() has been called successfully + * beforehand). + * + * Return 0 on success and -1 on error with errno set to the error code. + */ +static int ntfs_mftmirr_load(ntfs_volume *vol) +{ + int err; + + vol->mftmirr_ni = ntfs_inode_open(vol, FILE_MFTMirr); + if (!vol->mftmirr_ni) { + ntfs_log_perror("Failed to open inode $MFTMirr"); + return -1; + } + + vol->mftmirr_na = ntfs_attr_open(vol->mftmirr_ni, AT_DATA, AT_UNNAMED, 0); + if (!vol->mftmirr_na) { + ntfs_log_perror("Failed to open $MFTMirr/$DATA"); + goto error_exit; + } + + if (ntfs_attr_map_runlist(vol->mftmirr_na, 0) < 0) { + ntfs_log_perror("Failed to map runlist of $MFTMirr/$DATA"); + goto error_exit; + } + + return 0; + +error_exit: + err = errno; + if (vol->mftmirr_na) { + ntfs_attr_close(vol->mftmirr_na); + vol->mftmirr_na = NULL; + } + ntfs_inode_close(vol->mftmirr_ni); + vol->mftmirr_ni = NULL; + errno = err; + return -1; +} + +/** + * ntfs_volume_startup - allocate and setup an ntfs volume + * @dev: device to open + * @flags: optional mount flags + * + * Load, verify, and parse bootsector; load and setup $MFT and $MFTMirr. After + * calling this function, the volume is setup sufficiently to call all read + * and write access functions provided by the library. + * + * Return the allocated volume structure on success and NULL on error with + * errno set to the error code. + */ +ntfs_volume *ntfs_volume_startup(struct ntfs_device *dev, unsigned long flags) +{ + LCN mft_zone_size, mft_lcn; + s64 br; + ntfs_volume *vol; + NTFS_BOOT_SECTOR *bs; + int eo; + + if (!dev || !dev->d_ops || !dev->d_name) { + errno = EINVAL; + ntfs_log_perror("%s: dev = %p", __FUNCTION__, dev); + return NULL; + } + + bs = ntfs_malloc(sizeof(NTFS_BOOT_SECTOR)); + if (!bs) + return NULL; + + /* Allocate the volume structure. */ + vol = ntfs_volume_alloc(); + if (!vol) + goto error_exit; + + /* Create the default upcase table. */ + vol->upcase_len = 65536; + vol->upcase = ntfs_malloc(vol->upcase_len * sizeof(ntfschar)); + if (!vol->upcase) + goto error_exit; + + ntfs_upcase_table_build(vol->upcase, + vol->upcase_len * sizeof(ntfschar)); + + if (flags & MS_RDONLY) + NVolSetReadOnly(vol); + + /* ...->open needs bracketing to compile with glibc 2.7 */ + if ((dev->d_ops->open)(dev, NVolReadOnly(vol) ? O_RDONLY: O_RDWR)) { + ntfs_log_perror("Error opening '%s'", dev->d_name); + goto error_exit; + } + /* Attach the device to the volume. */ + vol->dev = dev; + + /* Now read the bootsector. */ + br = ntfs_pread(dev, 0, sizeof(NTFS_BOOT_SECTOR), bs); + if (br != sizeof(NTFS_BOOT_SECTOR)) { + if (br != -1) + errno = EINVAL; + if (!br) + ntfs_log_error("Failed to read bootsector (size=0)\n"); + else + ntfs_log_perror("Error reading bootsector"); + goto error_exit; + } + if (!ntfs_boot_sector_is_ntfs(bs)) { + errno = EINVAL; + goto error_exit; + } + if (ntfs_boot_sector_parse(vol, bs) < 0) + goto error_exit; + + free(bs); + bs = NULL; + /* Now set the device block size to the sector size. */ + if (ntfs_device_block_size_set(vol->dev, vol->sector_size)) + ntfs_log_debug("Failed to set the device block size to the " + "sector size. This may affect performance " + "but should be harmless otherwise. Error: " + "%s\n", strerror(errno)); + + /* We now initialize the cluster allocator. */ + vol->full_zones = 0; + mft_zone_size = vol->nr_clusters >> 3; /* 12.5% */ + + /* Setup the mft zone. */ + vol->mft_zone_start = vol->mft_zone_pos = vol->mft_lcn; + ntfs_log_debug("mft_zone_pos = 0x%llx\n", (long long)vol->mft_zone_pos); + + /* + * Calculate the mft_lcn for an unmodified NTFS volume (see mkntfs + * source) and if the actual mft_lcn is in the expected place or even + * further to the front of the volume, extend the mft_zone to cover the + * beginning of the volume as well. This is in order to protect the + * area reserved for the mft bitmap as well within the mft_zone itself. + * On non-standard volumes we don't protect it as the overhead would be + * higher than the speed increase we would get by doing it. + */ + mft_lcn = (8192 + 2 * vol->cluster_size - 1) / vol->cluster_size; + if (mft_lcn * vol->cluster_size < 16 * 1024) + mft_lcn = (16 * 1024 + vol->cluster_size - 1) / + vol->cluster_size; + if (vol->mft_zone_start <= mft_lcn) + vol->mft_zone_start = 0; + ntfs_log_debug("mft_zone_start = 0x%llx\n", (long long)vol->mft_zone_start); + + /* + * Need to cap the mft zone on non-standard volumes so that it does + * not point outside the boundaries of the volume. We do this by + * halving the zone size until we are inside the volume. + */ + vol->mft_zone_end = vol->mft_lcn + mft_zone_size; + while (vol->mft_zone_end >= vol->nr_clusters) { + mft_zone_size >>= 1; + vol->mft_zone_end = vol->mft_lcn + mft_zone_size; + } + ntfs_log_debug("mft_zone_end = 0x%llx\n", (long long)vol->mft_zone_end); + + /* + * Set the current position within each data zone to the start of the + * respective zone. + */ + vol->data1_zone_pos = vol->mft_zone_end; + ntfs_log_debug("data1_zone_pos = %lld\n", (long long)vol->data1_zone_pos); + vol->data2_zone_pos = 0; + ntfs_log_debug("data2_zone_pos = %lld\n", (long long)vol->data2_zone_pos); + + /* Set the mft data allocation position to mft record 24. */ + vol->mft_data_pos = 24; + + /* + * The cluster allocator is now fully operational. + */ + + /* Need to setup $MFT so we can use the library read functions. */ + if (ntfs_mft_load(vol) < 0) { + ntfs_log_perror("Failed to load $MFT"); + goto error_exit; + } + + /* Need to setup $MFTMirr so we can use the write functions, too. */ + if (ntfs_mftmirr_load(vol) < 0) { + ntfs_log_perror("Failed to load $MFTMirr"); + goto error_exit; + } + return vol; +error_exit: + eo = errno; + free(bs); + if (vol) + __ntfs_volume_release(vol); + errno = eo; + return NULL; +} + +/** + * ntfs_volume_check_logfile - check logfile on target volume + * @vol: volume on which to check logfile + * + * Return 0 on success and -1 on error with errno set error code. + */ +static int ntfs_volume_check_logfile(ntfs_volume *vol) +{ + ntfs_inode *ni; + ntfs_attr *na = NULL; + RESTART_PAGE_HEADER *rp = NULL; + int err = 0; + + ni = ntfs_inode_open(vol, FILE_LogFile); + if (!ni) { + ntfs_log_perror("Failed to open inode FILE_LogFile"); + errno = EIO; + return -1; + } + + na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0); + if (!na) { + ntfs_log_perror("Failed to open $FILE_LogFile/$DATA"); + err = EIO; + goto out; + } + + if (!ntfs_check_logfile(na, &rp) || !ntfs_is_logfile_clean(na, rp)) + err = EOPNOTSUPP; + free(rp); + ntfs_attr_close(na); +out: + if (ntfs_inode_close(ni)) + ntfs_error_set(&err); + if (err) { + errno = err; + return -1; + } + return 0; +} + +/** + * ntfs_hiberfile_open - Find and open '/hiberfil.sys' + * @vol: An ntfs volume obtained from ntfs_mount + * + * Return: inode Success, hiberfil.sys is valid + * NULL hiberfil.sys doesn't exist or some other error occurred + */ +static ntfs_inode *ntfs_hiberfile_open(ntfs_volume *vol) +{ + u64 inode; + ntfs_inode *ni_root; + ntfs_inode *ni_hibr = NULL; + ntfschar *unicode = NULL; + int unicode_len; + const char *hiberfile = "hiberfil.sys"; + + if (!vol) { + errno = EINVAL; + return NULL; + } + + ni_root = ntfs_inode_open(vol, FILE_root); + if (!ni_root) { + ntfs_log_debug("Couldn't open the root directory.\n"); + return NULL; + } + + unicode_len = ntfs_mbstoucs(hiberfile, &unicode); + if (unicode_len < 0) { + ntfs_log_perror("Couldn't convert 'hiberfil.sys' to Unicode"); + goto out; + } + + inode = ntfs_inode_lookup_by_name(ni_root, unicode, unicode_len); + if (inode == (u64)-1) { + ntfs_log_debug("Couldn't find file '%s'.\n", hiberfile); + goto out; + } + + inode = MREF(inode); + ni_hibr = ntfs_inode_open(vol, inode); + if (!ni_hibr) { + ntfs_log_debug("Couldn't open inode %lld.\n", (long long)inode); + goto out; + } +out: + if (ntfs_inode_close(ni_root)) { + ntfs_inode_close(ni_hibr); + ni_hibr = NULL; + } + free(unicode); + return ni_hibr; +} + + +#define NTFS_HIBERFILE_HEADER_SIZE 4096 + +/** + * ntfs_volume_check_hiberfile - check hiberfil.sys whether Windows is + * hibernated on the target volume + * @vol: volume on which to check hiberfil.sys + * + * Return: 0 if Windows isn't hibernated for sure + * -1 otherwise and errno is set to the appropriate value + */ +int ntfs_volume_check_hiberfile(ntfs_volume *vol, int verbose) +{ + ntfs_inode *ni; + ntfs_attr *na = NULL; + int bytes_read, err; + char *buf = NULL; + + ni = ntfs_hiberfile_open(vol); + if (!ni) { + if (errno == ENOENT) + return 0; + return -1; + } + + buf = ntfs_malloc(NTFS_HIBERFILE_HEADER_SIZE); + if (!buf) + goto out; + + na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0); + if (!na) { + ntfs_log_perror("Failed to open hiberfil.sys data attribute"); + goto out; + } + + bytes_read = ntfs_attr_pread(na, 0, NTFS_HIBERFILE_HEADER_SIZE, buf); + if (bytes_read == -1) { + ntfs_log_perror("Failed to read hiberfil.sys"); + goto out; + } + if (bytes_read < NTFS_HIBERFILE_HEADER_SIZE) { + if (verbose) + ntfs_log_error("Hibernated non-system partition, " + "refused to mount.\n"); + errno = EPERM; + goto out; + } + if (memcmp(buf, "hibr", 4) == 0) { + if (verbose) + ntfs_log_error("Windows is hibernated, refused to mount.\n"); + errno = EPERM; + goto out; + } + /* All right, all header bytes are zero */ + errno = 0; +out: + if (na) + ntfs_attr_close(na); + free(buf); + err = errno; + if (ntfs_inode_close(ni)) + ntfs_error_set(&err); + errno = err; + return errno ? -1 : 0; +} + +/* + * Make sure a LOGGED_UTILITY_STREAM attribute named "$TXF_DATA" + * on the root directory is resident. + * When it is non-resident, the partition cannot be mounted on Vista + * (see http://support.microsoft.com/kb/974729) + * + * We take care to avoid this situation, however this can be a + * consequence of having used an older version (including older + * Windows version), so we had better fix it. + * + * Returns 0 if unneeded or successful + * -1 if there was an error, explained by errno + */ + +static int fix_txf_data(ntfs_volume *vol) +{ + void *txf_data; + s64 txf_data_size; + ntfs_inode *ni; + ntfs_attr *na; + int res; + + res = 0; + ntfs_log_debug("Loading root directory\n"); + ni = ntfs_inode_open(vol, FILE_root); + if (!ni) { + ntfs_log_perror("Failed to open root directory"); + res = -1; + } else { + /* Get the $TXF_DATA attribute */ + na = ntfs_attr_open(ni, AT_LOGGED_UTILITY_STREAM, TXF_DATA, 9); + if (na) { + if (NAttrNonResident(na)) { + /* + * Fix the attribute by truncating, then + * rewriting it. + */ + ntfs_log_debug("Making $TXF_DATA resident\n"); + txf_data = ntfs_attr_readall(ni, + AT_LOGGED_UTILITY_STREAM, + TXF_DATA, 9, &txf_data_size); + if (txf_data) { + if (ntfs_attr_truncate(na, 0) + || (ntfs_attr_pwrite(na, 0, + txf_data_size, txf_data) + != txf_data_size)) + res = -1; + free(txf_data); + } + if (res) + ntfs_log_error("Failed to make $TXF_DATA resident\n"); + else + ntfs_log_error("$TXF_DATA made resident\n"); + } + ntfs_attr_close(na); + } + if (ntfs_inode_close(ni)) { + ntfs_log_perror("Failed to close root"); + res = -1; + } + } + return (res); +} + +/** + * ntfs_device_mount - open ntfs volume + * @dev: device to open + * @flags: optional mount flags + * + * This function mounts an ntfs volume. @dev should describe the device which + * to mount as the ntfs volume. + * + * @flags is an optional second parameter. The same flags are used as for + * the mount system call (man 2 mount). Currently only the following flag + * is implemented: + * MS_RDONLY - mount volume read-only + * + * The function opens the device @dev and verifies that it contains a valid + * bootsector. Then, it allocates an ntfs_volume structure and initializes + * some of the values inside the structure from the information stored in the + * bootsector. It proceeds to load the necessary system files and completes + * setting up the structure. + * + * Return the allocated volume structure on success and NULL on error with + * errno set to the error code. + */ +ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, unsigned long flags) +{ + s64 l; + ntfs_volume *vol; + u8 *m = NULL, *m2 = NULL; + ntfs_attr_search_ctx *ctx = NULL; + ntfs_inode *ni; + ntfs_attr *na; + ATTR_RECORD *a; + VOLUME_INFORMATION *vinf; + ntfschar *vname; + int i, j, eo; + u32 u; + + vol = ntfs_volume_startup(dev, flags); + if (!vol) + return NULL; + + /* Load data from $MFT and $MFTMirr and compare the contents. */ + m = ntfs_malloc(vol->mftmirr_size << vol->mft_record_size_bits); + m2 = ntfs_malloc(vol->mftmirr_size << vol->mft_record_size_bits); + if (!m || !m2) + goto error_exit; + + l = ntfs_attr_mst_pread(vol->mft_na, 0, vol->mftmirr_size, + vol->mft_record_size, m); + if (l != vol->mftmirr_size) { + if (l == -1) + ntfs_log_perror("Failed to read $MFT"); + else { + ntfs_log_error("Failed to read $MFT, unexpected length " + "(%lld != %d).\n", (long long)l, + vol->mftmirr_size); + errno = EIO; + } + goto error_exit; + } + l = ntfs_attr_mst_pread(vol->mftmirr_na, 0, vol->mftmirr_size, + vol->mft_record_size, m2); + if (l != vol->mftmirr_size) { + if (l == -1) { + ntfs_log_perror("Failed to read $MFTMirr"); + goto error_exit; + } + vol->mftmirr_size = l; + } + ntfs_log_debug("Comparing $MFTMirr to $MFT...\n"); + for (i = 0; i < vol->mftmirr_size; ++i) { + MFT_RECORD *mrec, *mrec2; + const char *ESTR[12] = { "$MFT", "$MFTMirr", "$LogFile", + "$Volume", "$AttrDef", "root directory", "$Bitmap", + "$Boot", "$BadClus", "$Secure", "$UpCase", "$Extend" }; + const char *s; + + if (i < 12) + s = ESTR[i]; + else if (i < 16) + s = "system file"; + else + s = "mft record"; + + mrec = (MFT_RECORD*)(m + i * vol->mft_record_size); + if (mrec->flags & MFT_RECORD_IN_USE) { + if (ntfs_is_baad_recordp(mrec)) { + ntfs_log_error("$MFT error: Incomplete multi " + "sector transfer detected in " + "'%s'.\n", s); + goto io_error_exit; + } + if (!ntfs_is_mft_recordp(mrec)) { + ntfs_log_error("$MFT error: Invalid mft " + "record for '%s'.\n", s); + goto io_error_exit; + } + } + mrec2 = (MFT_RECORD*)(m2 + i * vol->mft_record_size); + if (mrec2->flags & MFT_RECORD_IN_USE) { + if (ntfs_is_baad_recordp(mrec2)) { + ntfs_log_error("$MFTMirr error: Incomplete " + "multi sector transfer " + "detected in '%s'.\n", s); + goto io_error_exit; + } + if (!ntfs_is_mft_recordp(mrec2)) { + ntfs_log_error("$MFTMirr error: Invalid mft " + "record for '%s'.\n", s); + goto io_error_exit; + } + } + if (memcmp(mrec, mrec2, ntfs_mft_record_get_data_size(mrec))) { + ntfs_log_error("$MFTMirr does not match $MFT (record " + "%d).\n", i); + goto io_error_exit; + } + } + + free(m2); + free(m); + m = m2 = NULL; + + /* Now load the bitmap from $Bitmap. */ + ntfs_log_debug("Loading $Bitmap...\n"); + vol->lcnbmp_ni = ntfs_inode_open(vol, FILE_Bitmap); + if (!vol->lcnbmp_ni) { + ntfs_log_perror("Failed to open inode FILE_Bitmap"); + goto error_exit; + } + + vol->lcnbmp_na = ntfs_attr_open(vol->lcnbmp_ni, AT_DATA, AT_UNNAMED, 0); + if (!vol->lcnbmp_na) { + ntfs_log_perror("Failed to open ntfs attribute"); + goto error_exit; + } + + if (vol->lcnbmp_na->data_size > vol->lcnbmp_na->allocated_size) { + ntfs_log_error("Corrupt cluster map size (%lld > %lld)\n", + (long long)vol->lcnbmp_na->data_size, + (long long)vol->lcnbmp_na->allocated_size); + goto io_error_exit; + } + + /* Now load the upcase table from $UpCase. */ + ntfs_log_debug("Loading $UpCase...\n"); + ni = ntfs_inode_open(vol, FILE_UpCase); + if (!ni) { + ntfs_log_perror("Failed to open inode FILE_UpCase"); + goto error_exit; + } + /* Get an ntfs attribute for $UpCase/$DATA. */ + na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0); + if (!na) { + ntfs_log_perror("Failed to open ntfs attribute"); + goto error_exit; + } + /* + * Note: Normally, the upcase table has a length equal to 65536 + * 2-byte Unicode characters but allow for different cases, so no + * checks done. Just check we don't overflow 32-bits worth of Unicode + * characters. + */ + if (na->data_size & ~0x1ffffffffULL) { + ntfs_log_error("Error: Upcase table is too big (max 32-bit " + "allowed).\n"); + errno = EINVAL; + goto error_exit; + } + if (vol->upcase_len != na->data_size >> 1) { + vol->upcase_len = na->data_size >> 1; + /* Throw away default table. */ + free(vol->upcase); + vol->upcase = ntfs_malloc(na->data_size); + if (!vol->upcase) + goto error_exit; + } + /* Read in the $DATA attribute value into the buffer. */ + l = ntfs_attr_pread(na, 0, na->data_size, vol->upcase); + if (l != na->data_size) { + ntfs_log_error("Failed to read $UpCase, unexpected length " + "(%lld != %lld).\n", (long long)l, + (long long)na->data_size); + errno = EIO; + goto error_exit; + } + /* Done with the $UpCase mft record. */ + ntfs_attr_close(na); + if (ntfs_inode_close(ni)) { + ntfs_log_perror("Failed to close $UpCase"); + goto error_exit; + } + + /* + * Now load $Volume and set the version information and flags in the + * vol structure accordingly. + */ + ntfs_log_debug("Loading $Volume...\n"); + vol->vol_ni = ntfs_inode_open(vol, FILE_Volume); + if (!vol->vol_ni) { + ntfs_log_perror("Failed to open inode FILE_Volume"); + goto error_exit; + } + /* Get a search context for the $Volume/$VOLUME_INFORMATION lookup. */ + ctx = ntfs_attr_get_search_ctx(vol->vol_ni, NULL); + if (!ctx) + goto error_exit; + + /* Find the $VOLUME_INFORMATION attribute. */ + if (ntfs_attr_lookup(AT_VOLUME_INFORMATION, AT_UNNAMED, 0, 0, 0, NULL, + 0, ctx)) { + ntfs_log_perror("$VOLUME_INFORMATION attribute not found in " + "$Volume"); + goto error_exit; + } + a = ctx->attr; + /* Has to be resident. */ + if (a->non_resident) { + ntfs_log_error("Attribute $VOLUME_INFORMATION must be " + "resident but it isn't.\n"); + errno = EIO; + goto error_exit; + } + /* Get a pointer to the value of the attribute. */ + vinf = (VOLUME_INFORMATION*)(le16_to_cpu(a->value_offset) + (char*)a); + /* Sanity checks. */ + if ((char*)vinf + le32_to_cpu(a->value_length) > (char*)ctx->mrec + + le32_to_cpu(ctx->mrec->bytes_in_use) || + le16_to_cpu(a->value_offset) + le32_to_cpu( + a->value_length) > le32_to_cpu(a->length)) { + ntfs_log_error("$VOLUME_INFORMATION in $Volume is corrupt.\n"); + errno = EIO; + goto error_exit; + } + /* Setup vol from the volume information attribute value. */ + vol->major_ver = vinf->major_ver; + vol->minor_ver = vinf->minor_ver; + /* Do not use le16_to_cpu() macro here as our VOLUME_FLAGS are + defined using cpu_to_le16() macro and hence are consistent. */ + vol->flags = vinf->flags; + /* + * Reinitialize the search context for the $Volume/$VOLUME_NAME lookup. + */ + ntfs_attr_reinit_search_ctx(ctx); + if (ntfs_attr_lookup(AT_VOLUME_NAME, AT_UNNAMED, 0, 0, 0, NULL, 0, + ctx)) { + if (errno != ENOENT) { + ntfs_log_perror("Failed to lookup of $VOLUME_NAME in " + "$Volume failed"); + goto error_exit; + } + /* + * Attribute not present. This has been seen in the field. + * Treat this the same way as if the attribute was present but + * had zero length. + */ + vol->vol_name = ntfs_malloc(1); + if (!vol->vol_name) + goto error_exit; + vol->vol_name[0] = '\0'; + } else { + a = ctx->attr; + /* Has to be resident. */ + if (a->non_resident) { + ntfs_log_error("$VOLUME_NAME must be resident.\n"); + errno = EIO; + goto error_exit; + } + /* Get a pointer to the value of the attribute. */ + vname = (ntfschar*)(le16_to_cpu(a->value_offset) + (char*)a); + u = le32_to_cpu(a->value_length) / 2; + /* + * Convert Unicode volume name to current locale multibyte + * format. + */ + vol->vol_name = NULL; + if (ntfs_ucstombs(vname, u, &vol->vol_name, 0) == -1) { + ntfs_log_perror("Volume name could not be converted " + "to current locale"); + ntfs_log_debug("Forcing name into ASCII by replacing " + "non-ASCII characters with underscores.\n"); + vol->vol_name = ntfs_malloc(u + 1); + if (!vol->vol_name) + goto error_exit; + + for (j = 0; j < (s32)u; j++) { + u16 uc = le16_to_cpu(vname[j]); + if (uc > 0xff) + uc = (u16)'_'; + vol->vol_name[j] = (char)uc; + } + vol->vol_name[u] = '\0'; + } + } + ntfs_attr_put_search_ctx(ctx); + ctx = NULL; + /* Now load the attribute definitions from $AttrDef. */ + ntfs_log_debug("Loading $AttrDef...\n"); + ni = ntfs_inode_open(vol, FILE_AttrDef); + if (!ni) { + ntfs_log_perror("Failed to open $AttrDef"); + goto error_exit; + } + /* Get an ntfs attribute for $AttrDef/$DATA. */ + na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0); + if (!na) { + ntfs_log_perror("Failed to open ntfs attribute"); + goto error_exit; + } + /* Check we don't overflow 32-bits. */ + if (na->data_size > 0xffffffffLL) { + ntfs_log_error("Attribute definition table is too big (max " + "32-bit allowed).\n"); + errno = EINVAL; + goto error_exit; + } + vol->attrdef_len = na->data_size; + vol->attrdef = ntfs_malloc(na->data_size); + if (!vol->attrdef) + goto error_exit; + /* Read in the $DATA attribute value into the buffer. */ + l = ntfs_attr_pread(na, 0, na->data_size, vol->attrdef); + if (l != na->data_size) { + ntfs_log_error("Failed to read $AttrDef, unexpected length " + "(%lld != %lld).\n", (long long)l, + (long long)na->data_size); + errno = EIO; + goto error_exit; + } + /* Done with the $AttrDef mft record. */ + ntfs_attr_close(na); + if (ntfs_inode_close(ni)) { + ntfs_log_perror("Failed to close $AttrDef"); + goto error_exit; + } + /* + * Check for dirty logfile and hibernated Windows. + * We care only about read-write mounts. + */ + if (!(flags & MS_RDONLY)) { + if (!(flags & MS_IGNORE_HIBERFILE) && + ntfs_volume_check_hiberfile(vol, 1) < 0) + goto error_exit; + if (ntfs_volume_check_logfile(vol) < 0) { + if (!(flags & MS_RECOVER)) + goto error_exit; + ntfs_log_info("The file system wasn't safely " + "closed on Windows. Fixing.\n"); + if (ntfs_logfile_reset(vol)) + goto error_exit; + } + } + /* make $TXF_DATA resident if present on the root directory */ + if (!NVolReadOnly(vol) && fix_txf_data(vol)) + goto error_exit; + + return vol; +io_error_exit: + errno = EIO; +error_exit: + eo = errno; + if (ctx) + ntfs_attr_put_search_ctx(ctx); + free(m); + free(m2); + __ntfs_volume_release(vol); + errno = eo; + return NULL; +} + +/** + * ntfs_mount - open ntfs volume + * @name: name of device/file to open + * @flags: optional mount flags + * + * This function mounts an ntfs volume. @name should contain the name of the + * device/file to mount as the ntfs volume. + * + * @flags is an optional second parameter. The same flags are used as for + * the mount system call (man 2 mount). Currently only the following flags + * is implemented: + * MS_RDONLY - mount volume read-only + * + * The function opens the device or file @name and verifies that it contains a + * valid bootsector. Then, it allocates an ntfs_volume structure and initializes + * some of the values inside the structure from the information stored in the + * bootsector. It proceeds to load the necessary system files and completes + * setting up the structure. + * + * Return the allocated volume structure on success and NULL on error with + * errno set to the error code. + * + * Note, that a copy is made of @name, and hence it can be discarded as + * soon as the function returns. + */ +ntfs_volume *ntfs_mount(const char *name __attribute__((unused)), + unsigned long flags __attribute__((unused))) +{ +#ifndef NO_NTFS_DEVICE_DEFAULT_IO_OPS + struct ntfs_device *dev; + ntfs_volume *vol; + + /* Allocate an ntfs_device structure. */ + dev = ntfs_device_alloc(name, 0, &ntfs_device_default_io_ops, NULL); + if (!dev) + return NULL; + /* Call ntfs_device_mount() to do the actual mount. */ + vol = ntfs_device_mount(dev, flags); + if (!vol) { + int eo = errno; + ntfs_device_free(dev); + errno = eo; + } else + ntfs_create_lru_caches(vol); + return vol; +#else + /* + * ntfs_mount() makes no sense if NO_NTFS_DEVICE_DEFAULT_IO_OPS is + * defined as there are no device operations available in libntfs in + * this case. + */ + errno = EOPNOTSUPP; + return NULL; +#endif +} + +/** + * ntfs_umount - close ntfs volume + * @vol: address of ntfs_volume structure of volume to close + * @force: if true force close the volume even if it is busy + * + * Deallocate all structures (including @vol itself) associated with the ntfs + * volume @vol. + * + * Return 0 on success. On error return -1 with errno set appropriately + * (most likely to one of EAGAIN, EBUSY or EINVAL). The EAGAIN error means that + * an operation is in progress and if you try the close later the operation + * might be completed and the close succeed. + * + * If @force is true (i.e. not zero) this function will close the volume even + * if this means that data might be lost. + * + * @vol must have previously been returned by a call to ntfs_mount(). + * + * @vol itself is deallocated and should no longer be dereferenced after this + * function returns success. If it returns an error then nothing has been done + * so it is safe to continue using @vol. + */ +int ntfs_umount(ntfs_volume *vol, const BOOL force __attribute__((unused))) +{ + struct ntfs_device *dev; + int ret; + + if (!vol) { + errno = EINVAL; + return -1; + } + dev = vol->dev; + ret = __ntfs_volume_release(vol); + ntfs_device_free(dev); + return ret; +} + +#ifdef HAVE_MNTENT_H + +#ifndef HAVE_REALPATH +/** + * realpath - If there is no realpath on the system + */ +static char *realpath(const char *path, char *resolved_path) +{ + strncpy(resolved_path, path, PATH_MAX); + resolved_path[PATH_MAX] = '\0'; + return resolved_path; +} +#endif + +/** + * ntfs_mntent_check - desc + * + * If you are wanting to use this, you actually wanted to use + * ntfs_check_if_mounted(), you just didn't realize. (-: + * + * See description of ntfs_check_if_mounted(), below. + */ +static int ntfs_mntent_check(const char *file, unsigned long *mnt_flags) +{ + struct mntent *mnt; + char *real_file = NULL, *real_fsname = NULL; + FILE *f; + int err = 0; + + real_file = ntfs_malloc(PATH_MAX + 1); + if (!real_file) + return -1; + real_fsname = ntfs_malloc(PATH_MAX + 1); + if (!real_fsname) { + err = errno; + goto exit; + } + if (!realpath(file, real_file)) { + err = errno; + goto exit; + } + if (!(f = setmntent(MOUNTED, "r"))) { + err = errno; + goto exit; + } + while ((mnt = getmntent(f))) { + if (!realpath(mnt->mnt_fsname, real_fsname)) + continue; + if (!strcmp(real_file, real_fsname)) + break; + } + endmntent(f); + if (!mnt) + goto exit; + *mnt_flags = NTFS_MF_MOUNTED; + if (!strcmp(mnt->mnt_dir, "/")) + *mnt_flags |= NTFS_MF_ISROOT; +#ifdef HAVE_HASMNTOPT + if (hasmntopt(mnt, "ro") && !hasmntopt(mnt, "rw")) + *mnt_flags |= NTFS_MF_READONLY; +#endif +exit: + free(real_file); + free(real_fsname); + if (err) { + errno = err; + return -1; + } + return 0; +} +#endif /* HAVE_MNTENT_H */ + +/** + * ntfs_check_if_mounted - check if an ntfs volume is currently mounted + * @file: device file to check + * @mnt_flags: pointer into which to return the ntfs mount flags (see volume.h) + * + * If the running system does not support the {set,get,end}mntent() calls, + * just return 0 and set *@mnt_flags to zero. + * + * When the system does support the calls, ntfs_check_if_mounted() first tries + * to find the device @file in /etc/mtab (or wherever this is kept on the + * running system). If it is not found, assume the device is not mounted and + * return 0 and set *@mnt_flags to zero. + * + * If the device @file is found, set the NTFS_MF_MOUNTED flags in *@mnt_flags. + * + * Further if @file is mounted as the file system root ("/"), set the flag + * NTFS_MF_ISROOT in *@mnt_flags. + * + * Finally, check if the file system is mounted read-only, and if so set the + * NTFS_MF_READONLY flag in *@mnt_flags. + * + * On success return 0 with *@mnt_flags set to the ntfs mount flags. + * + * On error return -1 with errno set to the error code. + */ +int ntfs_check_if_mounted(const char *file __attribute__((unused)), + unsigned long *mnt_flags) +{ + *mnt_flags = 0; +#ifdef HAVE_MNTENT_H + return ntfs_mntent_check(file, mnt_flags); +#else + return 0; +#endif +} + +/** + * ntfs_version_is_supported - check if NTFS version is supported. + * @vol: ntfs volume whose version we're interested in. + * + * The function checks if the NTFS volume version is known or not. + * Version 1.1 and 1.2 are used by Windows NT3.x and NT4. + * Version 2.x is used by Windows 2000 Betas. + * Version 3.0 is used by Windows 2000. + * Version 3.1 is used by Windows XP, Windows Server 2003 and Longhorn. + * + * Return 0 if NTFS version is supported otherwise -1 with errno set. + * + * The following error codes are defined: + * EOPNOTSUPP - Unknown NTFS version + * EINVAL - Invalid argument + */ +int ntfs_version_is_supported(ntfs_volume *vol) +{ + u8 major, minor; + + if (!vol) { + errno = EINVAL; + return -1; + } + + major = vol->major_ver; + minor = vol->minor_ver; + + if (NTFS_V1_1(major, minor) || NTFS_V1_2(major, minor)) + return 0; + + if (NTFS_V2_X(major, minor)) + return 0; + + if (NTFS_V3_0(major, minor) || NTFS_V3_1(major, minor)) + return 0; + + errno = EOPNOTSUPP; + return -1; +} + +/** + * ntfs_logfile_reset - "empty" $LogFile data attribute value + * @vol: ntfs volume whose $LogFile we intend to reset. + * + * Fill the value of the $LogFile data attribute, i.e. the contents of + * the file, with 0xff's, thus marking the journal as empty. + * + * FIXME(?): We might need to zero the LSN field of every single mft + * record as well. (But, first try without doing that and see what + * happens, since chkdsk might pickup the pieces and do it for us...) + * + * On success return 0. + * + * On error return -1 with errno set to the error code. + */ +int ntfs_logfile_reset(ntfs_volume *vol) +{ + ntfs_inode *ni; + ntfs_attr *na; + int eo; + + if (!vol) { + errno = EINVAL; + return -1; + } + + ni = ntfs_inode_open(vol, FILE_LogFile); + if (!ni) { + ntfs_log_perror("Failed to open inode FILE_LogFile"); + return -1; + } + + na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0); + if (!na) { + eo = errno; + ntfs_log_perror("Failed to open $FILE_LogFile/$DATA"); + goto error_exit; + } + + if (ntfs_empty_logfile(na)) { + eo = errno; + ntfs_attr_close(na); + goto error_exit; + } + + ntfs_attr_close(na); + return ntfs_inode_close(ni); + +error_exit: + ntfs_inode_close(ni); + errno = eo; + return -1; +} + +/** + * ntfs_volume_write_flags - set the flags of an ntfs volume + * @vol: ntfs volume where we set the volume flags + * @flags: new flags + * + * Set the on-disk volume flags in the mft record of $Volume and + * on volume @vol to @flags. + * + * Return 0 if successful and -1 if not with errno set to the error code. + */ +int ntfs_volume_write_flags(ntfs_volume *vol, const le16 flags) +{ + ATTR_RECORD *a; + VOLUME_INFORMATION *c; + ntfs_attr_search_ctx *ctx; + int ret = -1; /* failure */ + + if (!vol || !vol->vol_ni) { + errno = EINVAL; + return -1; + } + /* Get a pointer to the volume information attribute. */ + ctx = ntfs_attr_get_search_ctx(vol->vol_ni, NULL); + if (!ctx) + return -1; + + if (ntfs_attr_lookup(AT_VOLUME_INFORMATION, AT_UNNAMED, 0, 0, 0, NULL, + 0, ctx)) { + ntfs_log_error("Attribute $VOLUME_INFORMATION was not found " + "in $Volume!\n"); + goto err_out; + } + a = ctx->attr; + /* Sanity check. */ + if (a->non_resident) { + ntfs_log_error("Attribute $VOLUME_INFORMATION must be resident " + "but it isn't.\n"); + errno = EIO; + goto err_out; + } + /* Get a pointer to the value of the attribute. */ + c = (VOLUME_INFORMATION*)(le16_to_cpu(a->value_offset) + (char*)a); + /* Sanity checks. */ + if ((char*)c + le32_to_cpu(a->value_length) > (char*)ctx->mrec + + le32_to_cpu(ctx->mrec->bytes_in_use) || + le16_to_cpu(a->value_offset) + + le32_to_cpu(a->value_length) > le32_to_cpu(a->length)) { + ntfs_log_error("Attribute $VOLUME_INFORMATION in $Volume is " + "corrupt!\n"); + errno = EIO; + goto err_out; + } + /* Set the volume flags. */ + vol->flags = c->flags = flags & VOLUME_FLAGS_MASK; + /* Write them to disk. */ + ntfs_inode_mark_dirty(vol->vol_ni); + if (ntfs_inode_sync(vol->vol_ni)) + goto err_out; + + ret = 0; /* success */ +err_out: + ntfs_attr_put_search_ctx(ctx); + return ret; +} + +int ntfs_volume_error(int err) +{ + int ret; + + switch (err) { + case 0: + ret = NTFS_VOLUME_OK; + break; + case EINVAL: + ret = NTFS_VOLUME_NOT_NTFS; + break; + case EIO: + ret = NTFS_VOLUME_CORRUPT; + break; + case EPERM: + ret = NTFS_VOLUME_HIBERNATED; + break; + case EOPNOTSUPP: + ret = NTFS_VOLUME_UNCLEAN_UNMOUNT; + break; + case EBUSY: + ret = NTFS_VOLUME_LOCKED; + break; + case ENXIO: + ret = NTFS_VOLUME_RAID; + break; + case EACCES: + ret = NTFS_VOLUME_NO_PRIVILEGE; + break; + default: + ret = NTFS_VOLUME_UNKNOWN_REASON; + break; + } + return ret; +} + + +void ntfs_mount_error(const char *volume, const char *mntpoint, int err) +{ + switch (err) { + case NTFS_VOLUME_NOT_NTFS: + ntfs_log_error(invalid_ntfs_msg, volume); + break; + case NTFS_VOLUME_CORRUPT: + ntfs_log_error("%s", corrupt_volume_msg); + break; + case NTFS_VOLUME_HIBERNATED: + ntfs_log_error(hibernated_volume_msg, volume, mntpoint); + break; + case NTFS_VOLUME_UNCLEAN_UNMOUNT: + ntfs_log_error("%s", unclean_journal_msg); + break; + case NTFS_VOLUME_LOCKED: + ntfs_log_error("%s", opened_volume_msg); + break; + case NTFS_VOLUME_RAID: + ntfs_log_error("%s", fakeraid_msg); + break; + case NTFS_VOLUME_NO_PRIVILEGE: + ntfs_log_error(access_denied_msg, volume); + break; + } +} + +int ntfs_set_locale(void) +{ + const char *locale; + + locale = setlocale(LC_ALL, ""); + if (!locale) { + locale = setlocale(LC_ALL, NULL); + ntfs_log_error("Couldn't set local environment, using default " + "'%s'.\n", locale); + return 1; + } + return 0; +} + +/* + * Feed the counts of free clusters and free mft records + */ + +int ntfs_volume_get_free_space(ntfs_volume *vol) +{ + ntfs_attr *na; + int ret; + + ret = -1; /* default return */ + vol->free_clusters = ntfs_attr_get_free_bits(vol->lcnbmp_na); + if (vol->free_clusters < 0) { + ntfs_log_perror("Failed to read NTFS $Bitmap"); + } else { + na = vol->mftbmp_na; + vol->free_mft_records = ntfs_attr_get_free_bits(na); + + if (vol->free_mft_records >= 0) + vol->free_mft_records += (na->allocated_size - na->data_size) << 3; + + if (vol->free_mft_records < 0) + ntfs_log_perror("Failed to calculate free MFT records"); + else + ret = 0; + } + return (ret); +} diff --git a/libntfs-3g/win32_io.c b/libntfs-3g/win32_io.c new file mode 100755 index 0000000..ed9fa52 --- a/dev/null +++ b/libntfs-3g/win32_io.c @@ -0,0 +1,1477 @@ +/* + * win32_io.c - A stdio-like disk I/O implementation for low-level disk access + * on Win32. Can access an NTFS volume while it is mounted. + * Originated from the Linux-NTFS project. + * + * Copyright (c) 2003-2004 Lode Leroy + * Copyright (c) 2003-2006 Anton Altaparmakov + * Copyright (c) 2004-2005 Yuval Fledel + * + * This program/include file 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/include file 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 (in the main directory of the NTFS-3G + * distribution in the file COPYING); if not, write to the Free Software + * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "config.h" + +#ifdef HAVE_WINDOWS_H +#include +#endif +#include + +#ifdef HAVE_STDIO_H +#include +#endif +#ifdef HAVE_CTYPE_H +#include +#endif +#ifdef HAVE_ERRNO_H +#include +#endif +#ifdef HAVE_FCNTL_H +#include +#endif + +/* Prevent volume.h from being be loaded, as it conflicts with winnt.h. */ +#define _NTFS_VOLUME_H +struct ntfs_volume; +typedef struct ntfs_volume ntfs_volume; + +#include "debug.h" +#include "types.h" +#include "device.h" + +#ifndef MAX_PATH +#define MAX_PATH 1024 +#endif + +#ifndef NTFS_BLOCK_SIZE +#define NTFS_BLOCK_SIZE 512 +#define NTFS_BLOCK_SIZE_BITS 9 +#endif + +#ifndef IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS +#define IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS 5636096 +#endif + +/* Windows 2k+ imports. */ +typedef HANDLE (WINAPI *LPFN_FINDFIRSTVOLUME)(LPTSTR, DWORD); +typedef BOOL (WINAPI *LPFN_FINDNEXTVOLUME)(HANDLE, LPTSTR, DWORD); +typedef BOOL (WINAPI *LPFN_FINDVOLUMECLOSE)(HANDLE); +typedef BOOL (WINAPI *LPFN_SETFILEPOINTEREX)(HANDLE, LARGE_INTEGER, + PLARGE_INTEGER, DWORD); + +static LPFN_FINDFIRSTVOLUME fnFindFirstVolume = NULL; +static LPFN_FINDNEXTVOLUME fnFindNextVolume = NULL; +static LPFN_FINDVOLUMECLOSE fnFindVolumeClose = NULL; +static LPFN_SETFILEPOINTEREX fnSetFilePointerEx = NULL; + +#ifdef UNICODE +#define FNPOSTFIX "W" +#else +#define FNPOSTFIX "A" +#endif + +/** + * struct win32_fd - + */ +typedef struct { + HANDLE handle; + s64 pos; /* Logical current position on the volume. */ + s64 part_start; + s64 part_length; + int part_hidden_sectors; + s64 geo_size, geo_cylinders; + DWORD geo_sectors, geo_heads; + HANDLE vol_handle; +} win32_fd; + +/** + * ntfs_w32error_to_errno - convert a win32 error code to the unix one + * @w32error: the win32 error code + * + * Limited to a relatively small but useful number of codes. + */ +static int ntfs_w32error_to_errno(unsigned int w32error) +{ + ntfs_log_trace("Converting w32error 0x%x.\n",w32error); + switch (w32error) { + case ERROR_INVALID_FUNCTION: + return EBADRQC; + case ERROR_FILE_NOT_FOUND: + case ERROR_PATH_NOT_FOUND: + case ERROR_INVALID_NAME: + return ENOENT; + case ERROR_TOO_MANY_OPEN_FILES: + return EMFILE; + case ERROR_ACCESS_DENIED: + return EACCES; + case ERROR_INVALID_HANDLE: + return EBADF; + case ERROR_NOT_ENOUGH_MEMORY: + return ENOMEM; + case ERROR_OUTOFMEMORY: + return ENOSPC; + case ERROR_INVALID_DRIVE: + case ERROR_BAD_UNIT: + return ENODEV; + case ERROR_WRITE_PROTECT: + return EROFS; + case ERROR_NOT_READY: + case ERROR_SHARING_VIOLATION: + return EBUSY; + case ERROR_BAD_COMMAND: + return EINVAL; + case ERROR_SEEK: + case ERROR_NEGATIVE_SEEK: + return ESPIPE; + case ERROR_NOT_SUPPORTED: + return EOPNOTSUPP; + case ERROR_BAD_NETPATH: + return ENOSHARE; + default: + /* generic message */ + return ENOMSG; + } +} + +/** + * libntfs_SetFilePointerEx - emulation for SetFilePointerEx() + * + * We use this to emulate SetFilePointerEx() when it is not present. This can + * happen since SetFilePointerEx() only exists in Win2k+. + */ +static BOOL WINAPI libntfs_SetFilePointerEx(HANDLE hFile, + LARGE_INTEGER liDistanceToMove, + PLARGE_INTEGER lpNewFilePointer, DWORD dwMoveMethod) +{ + liDistanceToMove.LowPart = SetFilePointer(hFile, + liDistanceToMove.LowPart, &liDistanceToMove.HighPart, + dwMoveMethod); + if (liDistanceToMove.LowPart == INVALID_SET_FILE_POINTER && + GetLastError() != NO_ERROR) { + if (lpNewFilePointer) + lpNewFilePointer->QuadPart = -1; + return FALSE; + } + if (lpNewFilePointer) + lpNewFilePointer->QuadPart = liDistanceToMove.QuadPart; + return TRUE; +} + +/** + * ntfs_device_win32_init_imports - initialize the function pointers + * + * The Find*Volume and SetFilePointerEx functions exist only on win2k+, as such + * we cannot just staticly import them. + * + * This function initializes the imports if the functions do exist and in the + * SetFilePointerEx case, we emulate the function ourselves if it is not + * present. + * + * Note: The values are cached, do be afraid to run it more than once. + */ +static void ntfs_device_win32_init_imports(void) +{ + HMODULE kernel32 = GetModuleHandle("kernel32"); + if (!kernel32) { + errno = ntfs_w32error_to_errno(GetLastError()); + ntfs_log_trace("kernel32.dll could not be imported.\n"); + } + if (!fnSetFilePointerEx) { + if (kernel32) + fnSetFilePointerEx = (LPFN_SETFILEPOINTEREX) + GetProcAddress(kernel32, + "SetFilePointerEx"); + /* + * If we did not get kernel32.dll or it is not Win2k+, emulate + * SetFilePointerEx(). + */ + if (!fnSetFilePointerEx) { + ntfs_log_debug("SetFilePonterEx() not found in " + "kernel32.dll: Enabling emulation.\n"); + fnSetFilePointerEx = libntfs_SetFilePointerEx; + } + } + /* Cannot do lookups if we could not get kernel32.dll... */ + if (!kernel32) + return; + if (!fnFindFirstVolume) + fnFindFirstVolume = (LPFN_FINDFIRSTVOLUME) + GetProcAddress(kernel32, "FindFirstVolume" + FNPOSTFIX); + if (!fnFindNextVolume) + fnFindNextVolume = (LPFN_FINDNEXTVOLUME) + GetProcAddress(kernel32, "FindNextVolume" + FNPOSTFIX); + if (!fnFindVolumeClose) + fnFindVolumeClose = (LPFN_FINDVOLUMECLOSE) + GetProcAddress(kernel32, "FindVolumeClose"); +} + +/** + * ntfs_device_unix_status_flags_to_win32 - convert unix->win32 open flags + * @flags: unix open status flags + * + * Supported flags are O_RDONLY, O_WRONLY and O_RDWR. + */ +static __inline__ int ntfs_device_unix_status_flags_to_win32(int flags) +{ + int win_mode; + + switch (flags & O_ACCMODE) { + case O_RDONLY: + win_mode = FILE_READ_DATA; + break; + case O_WRONLY: + win_mode = FILE_WRITE_DATA; + break; + case O_RDWR: + win_mode = FILE_READ_DATA | FILE_WRITE_DATA; + break; + default: + /* error */ + ntfs_log_trace("Unknown status flags.\n"); + win_mode = 0; + } + return win_mode; +} + + +/** + * ntfs_device_win32_simple_open_file - just open a file via win32 API + * @filename: name of the file to open + * @handle: pointer the a HANDLE in which to put the result + * @flags: unix open status flags + * @locking: will the function gain an exclusive lock on the file? + * + * Supported flags are O_RDONLY, O_WRONLY and O_RDWR. + * + * Return 0 if o.k. + * -1 if not, and errno set. In this case handle is trashed. + */ +static int ntfs_device_win32_simple_open_file(const char *filename, + HANDLE *handle, int flags, BOOL locking) +{ + *handle = CreateFile(filename, + ntfs_device_unix_status_flags_to_win32(flags), + locking ? 0 : (FILE_SHARE_WRITE | FILE_SHARE_READ), + NULL, OPEN_EXISTING, 0, NULL); + if (*handle == INVALID_HANDLE_VALUE) { + errno = ntfs_w32error_to_errno(GetLastError()); + ntfs_log_trace("CreateFile(%s) failed.\n", filename); + return -1; + } + return 0; +} + +/** + * ntfs_device_win32_lock - lock the volume + * @handle: a win32 HANDLE for a volume to lock + * + * Locking a volume means no one can access its contents. + * Exiting the process automatically unlocks the volume, except in old NT4s. + * + * Return 0 if o.k. + * -1 if not, and errno set. + */ +static int ntfs_device_win32_lock(HANDLE handle) +{ + DWORD i; + + if (!DeviceIoControl(handle, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &i, + NULL)) { + errno = ntfs_w32error_to_errno(GetLastError()); + ntfs_log_trace("Couldn't lock volume.\n"); + return -1; + } + ntfs_log_debug("Volume locked.\n"); + return 0; +} + +/** + * ntfs_device_win32_unlock - unlock the volume + * @handle: the win32 HANDLE which the volume was locked with + * + * Return 0 if o.k. + * -1 if not, and errno set. + */ +static int ntfs_device_win32_unlock(HANDLE handle) +{ + DWORD i; + + if (!DeviceIoControl(handle, FSCTL_UNLOCK_VOLUME, NULL, 0, NULL, 0, &i, + NULL)) { + errno = ntfs_w32error_to_errno(GetLastError()); + ntfs_log_trace("Couldn't unlock volume.\n"); + return -1; + } + ntfs_log_debug("Volume unlocked.\n"); + return 0; +} + +/** + * ntfs_device_win32_dismount - dismount a volume + * @handle: a win32 HANDLE for a volume to dismount + * + * Dismounting means the system will refresh the volume in the first change it + * gets. Usefull after altering the file structures. + * The volume must be locked by the current process while dismounting. + * A side effect is that the volume is also unlocked, but you must not rely om + * this. + * + * Return 0 if o.k. + * -1 if not, and errno set. + */ +static int ntfs_device_win32_dismount(HANDLE handle) +{ + DWORD i; + + if (!DeviceIoControl(handle, FSCTL_DISMOUNT_VOLUME, NULL, 0, NULL, 0, + &i, NULL)) { + errno = ntfs_w32error_to_errno(GetLastError()); + ntfs_log_trace("Couldn't dismount volume.\n"); + return -1; + } + ntfs_log_debug("Volume dismounted.\n"); + return 0; +} + +/** + * ntfs_device_win32_getsize - get file size via win32 API + * @handle: pointer the file HANDLE obtained via open + * + * Only works on ordinary files. + * + * Return The file size if o.k. + * -1 if not, and errno set. + */ +static s64 ntfs_device_win32_getsize(HANDLE handle) +{ + DWORD loword, hiword; + + loword = GetFileSize(handle, &hiword); + if (loword == INVALID_FILE_SIZE) { + errno = ntfs_w32error_to_errno(GetLastError()); + ntfs_log_trace("Couldn't get file size.\n"); + return -1; + } + return ((s64)hiword << 32) + loword; +} + +/** + * ntfs_device_win32_getdisklength - get disk size via win32 API + * @handle: pointer the file HANDLE obtained via open + * @argp: pointer to result buffer + * + * Only works on PhysicalDriveX type handles. + * + * Return The disk size if o.k. + * -1 if not, and errno set. + */ +static s64 ntfs_device_win32_getdisklength(HANDLE handle) +{ + GET_LENGTH_INFORMATION buf; + DWORD i; + + if (!DeviceIoControl(handle, IOCTL_DISK_GET_LENGTH_INFO, NULL, 0, &buf, + sizeof(buf), &i, NULL)) { + errno = ntfs_w32error_to_errno(GetLastError()); + ntfs_log_trace("Couldn't get disk length.\n"); + return -1; + } + ntfs_log_debug("Disk length: %lld.\n", buf.Length.QuadPart); + return buf.Length.QuadPart; +} + +/** + * ntfs_device_win32_getntfssize - get NTFS volume size via win32 API + * @handle: pointer the file HANDLE obtained via open + * @argp: pointer to result buffer + * + * Only works on NTFS volume handles. + * An annoying bug in windows is that an NTFS volume does not occupy the entire + * partition, namely not the last sector (which holds the backup boot sector, + * and normally not interesting). + * Use this function to get the length of the accessible space through a given + * volume handle. + * + * Return The volume size if o.k. + * -1 if not, and errno set. + */ +static s64 ntfs_device_win32_getntfssize(HANDLE handle) +{ + s64 rvl; +#ifdef FSCTL_GET_NTFS_VOLUME_DATA + DWORD i; + NTFS_VOLUME_DATA_BUFFER buf; + + if (!DeviceIoControl(handle, FSCTL_GET_NTFS_VOLUME_DATA, NULL, 0, &buf, + sizeof(buf), &i, NULL)) { + errno = ntfs_w32error_to_errno(GetLastError()); + ntfs_log_trace("Couldn't get NTFS volume length.\n"); + return -1; + } + rvl = buf.NumberSectors.QuadPart * buf.BytesPerSector; + ntfs_log_debug("NTFS volume length: 0x%llx.\n", (long long)rvl); +#else + errno = EINVAL; + rvl = -1; +#endif + return rvl; +} + +/** + * ntfs_device_win32_getgeo - get CHS information of a drive + * @handle: an open handle to the PhysicalDevice + * @fd: a win_fd structure that will be filled + * + * Return 0 if o.k. + * -1 if not, and errno set. + * + * In Windows NT+: fills size, sectors, and cylinders and sets heads to -1. + * In Windows XP+: fills size, sectors, cylinders, and heads. + * + * Note: In pre XP, this requires write permission, even though nothing is + * actually written. + * + * If fails, sets sectors, cylinders, heads, and size to -1. + */ +static int ntfs_device_win32_getgeo(HANDLE handle, win32_fd *fd) +{ + DWORD i; + BOOL rvl; + BYTE b[sizeof(DISK_GEOMETRY) + sizeof(DISK_PARTITION_INFO) + + sizeof(DISK_DETECTION_INFO) + 512]; + + rvl = DeviceIoControl(handle, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, NULL, + 0, &b, sizeof(b), &i, NULL); + if (rvl) { + ntfs_log_debug("GET_DRIVE_GEOMETRY_EX detected.\n"); + DISK_DETECTION_INFO *ddi = (PDISK_DETECTION_INFO) + (((PBYTE)(&((PDISK_GEOMETRY_EX)b)->Data)) + + (((PDISK_PARTITION_INFO) + (&((PDISK_GEOMETRY_EX)b)->Data))-> + SizeOfPartitionInfo)); + fd->geo_cylinders = ((DISK_GEOMETRY*)&b)->Cylinders.QuadPart; + fd->geo_sectors = ((DISK_GEOMETRY*)&b)->SectorsPerTrack; + fd->geo_size = ((DISK_GEOMETRY_EX*)&b)->DiskSize.QuadPart; + switch (ddi->DetectionType) { + case DetectInt13: + fd->geo_cylinders = ddi->Int13.MaxCylinders; + fd->geo_sectors = ddi->Int13.SectorsPerTrack; + fd->geo_heads = ddi->Int13.MaxHeads; + return 0; + case DetectExInt13: + fd->geo_cylinders = ddi->ExInt13.ExCylinders; + fd->geo_sectors = ddi->ExInt13.ExSectorsPerTrack; + fd->geo_heads = ddi->ExInt13.ExHeads; + return 0; + case DetectNone: + default: + break; + } + } else + fd->geo_heads = -1; + rvl = DeviceIoControl(handle, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, + &b, sizeof(b), &i, NULL); + if (rvl) { + ntfs_log_debug("GET_DRIVE_GEOMETRY detected.\n"); + fd->geo_cylinders = ((DISK_GEOMETRY*)&b)->Cylinders.QuadPart; + fd->geo_sectors = ((DISK_GEOMETRY*)&b)->SectorsPerTrack; + fd->geo_size = fd->geo_cylinders * fd->geo_sectors * + ((DISK_GEOMETRY*)&b)->TracksPerCylinder * + ((DISK_GEOMETRY*)&b)->BytesPerSector; + return 0; + } + errno = ntfs_w32error_to_errno(GetLastError()); + ntfs_log_trace("Couldn't retrieve disk geometry.\n"); + fd->geo_cylinders = -1; + fd->geo_sectors = -1; + fd->geo_size = -1; + return -1; +} + +/** + * ntfs_device_win32_open_file - open a file via win32 API + * @filename: name of the file to open + * @fd: pointer to win32 file device in which to put the result + * @flags: unix open status flags + * + * Return 0 if o.k. + * -1 if not, and errno set. + */ +static __inline__ int ntfs_device_win32_open_file(char *filename, win32_fd *fd, + int flags) +{ + HANDLE handle; + + if (ntfs_device_win32_simple_open_file(filename, &handle, flags, + FALSE)) { + /* open error */ + return -1; + } + /* fill fd */ + fd->handle = handle; + fd->part_start = 0; + fd->part_length = ntfs_device_win32_getsize(handle); + fd->pos = 0; + fd->part_hidden_sectors = -1; + fd->geo_size = -1; /* used as a marker that this is a file */ + fd->vol_handle = INVALID_HANDLE_VALUE; + return 0; +} + +/** + * ntfs_device_win32_open_drive - open a drive via win32 API + * @drive_id: drive to open + * @fd: pointer to win32 file device in which to put the result + * @flags: unix open status flags + * + * return 0 if o.k. + * -1 if not, and errno set. + */ +static __inline__ int ntfs_device_win32_open_drive(int drive_id, win32_fd *fd, + int flags) +{ + HANDLE handle; + int err; + char filename[MAX_PATH]; + + sprintf(filename, "\\\\.\\PhysicalDrive%d", drive_id); + if ((err = ntfs_device_win32_simple_open_file(filename, &handle, flags, + TRUE))) { + /* open error */ + return err; + } + /* store the drive geometry */ + ntfs_device_win32_getgeo(handle, fd); + /* Just to be sure */ + if (fd->geo_size == -1) + fd->geo_size = ntfs_device_win32_getdisklength(handle); + /* fill fd */ + fd->handle = handle; + fd->part_start = 0; + fd->part_length = fd->geo_size; + fd->pos = 0; + fd->part_hidden_sectors = -1; + fd->vol_handle = INVALID_HANDLE_VALUE; + return 0; +} + +/** + * ntfs_device_win32_open_volume_for_partition - find and open a volume + * + * Windows NT/2k/XP handles volumes instead of partitions. + * This function gets the partition details and return an open volume handle. + * That volume is the one whose only physical location on disk is the described + * partition. + * + * The function required Windows 2k/XP, otherwise it fails (gracefully). + * + * Return success: a valid open volume handle. + * fail : INVALID_HANDLE_VALUE + */ +static HANDLE ntfs_device_win32_open_volume_for_partition(unsigned int drive_id, + s64 part_offset, s64 part_length, int flags) +{ + HANDLE vol_find_handle; + TCHAR vol_name[MAX_PATH]; + + /* Make sure all the required imports exist. */ + if (!fnFindFirstVolume || !fnFindNextVolume || !fnFindVolumeClose) { + ntfs_log_trace("Required dll imports not found.\n"); + return INVALID_HANDLE_VALUE; + } + /* Start iterating through volumes. */ + ntfs_log_trace("Entering with drive_id=%d, part_offset=%lld, " + "path_length=%lld, flags=%d.\n", drive_id, + (unsigned long long)part_offset, + (unsigned long long)part_length, flags); + vol_find_handle = fnFindFirstVolume(vol_name, MAX_PATH); + /* If a valid handle could not be aquired, reply with "don't know". */ + if (vol_find_handle == INVALID_HANDLE_VALUE) { + ntfs_log_trace("FindFirstVolume failed.\n"); + return INVALID_HANDLE_VALUE; + } + do { + int vol_name_length; + HANDLE handle; + + /* remove trailing '/' from vol_name */ +#ifdef UNICODE + vol_name_length = wcslen(vol_name); +#else + vol_name_length = strlen(vol_name); +#endif + if (vol_name_length>0) + vol_name[vol_name_length-1]=0; + + ntfs_log_debug("Processing %s.\n", vol_name); + /* open the file */ + handle = CreateFile(vol_name, + ntfs_device_unix_status_flags_to_win32(flags), + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, + OPEN_EXISTING, 0, NULL); + if (handle != INVALID_HANDLE_VALUE) { + DWORD bytesReturned; +#define EXTENTS_SIZE sizeof(VOLUME_DISK_EXTENTS) + 9 * sizeof(DISK_EXTENT) + char extents[EXTENTS_SIZE]; + + /* Check physical locations. */ + if (DeviceIoControl(handle, + IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS, + NULL, 0, extents, EXTENTS_SIZE, + &bytesReturned, NULL)) { + if (((VOLUME_DISK_EXTENTS *)extents)-> + NumberOfDiskExtents == 1) { + DISK_EXTENT *extent = &(( + VOLUME_DISK_EXTENTS *) + extents)->Extents[0]; + if ((extent->DiskNumber==drive_id) && + (extent->StartingOffset. + QuadPart==part_offset) + && (extent-> + ExtentLength.QuadPart + == part_length)) { + /* + * Eureka! (Archimedes, 287 BC, + * "I have found it!") + */ + fnFindVolumeClose( + vol_find_handle); + return handle; + } + } + } + } else + ntfs_log_trace("getExtents() Failed.\n"); + } while (fnFindNextVolume(vol_find_handle, vol_name, MAX_PATH)); + /* End of iteration through volumes. */ + ntfs_log_trace("Closing, volume was not found.\n"); + fnFindVolumeClose(vol_find_handle); + return INVALID_HANDLE_VALUE; +} + +/** + * ntfs_device_win32_find_partition - locates partition details by id. + * @handle: HANDLE to the PhysicalDrive + * @partition_id: the partition number to locate + * @part_offset: pointer to where to put the offset to the partition + * @part_length: pointer to where to put the length of the partition + * @hidden_sectors: pointer to where to put the hidden sectors + * + * This function requires an open PhysicalDrive handle and a partition_id. + * If a partition with the required id is found on the supplied device, + * the partition attributes are returned back. + * + * Returns: TRUE if found, and sets the output parameters. + * FALSE if not and errno is set to the error code. + */ +static BOOL ntfs_device_win32_find_partition(HANDLE handle, DWORD partition_id, + s64 *part_offset, s64 *part_length, int *hidden_sectors) +{ + DRIVE_LAYOUT_INFORMATION *drive_layout; + unsigned int err, buf_size, part_count; + DWORD i; + + /* + * There is no way to know the required buffer, so if the ioctl fails, + * try doubling the buffer size each time until the ioctl succeeds. + */ + part_count = 8; + do { + buf_size = sizeof(DRIVE_LAYOUT_INFORMATION) + + part_count * sizeof(PARTITION_INFORMATION); + drive_layout = malloc(buf_size); + if (!drive_layout) { + errno = ENOMEM; + return FALSE; + } + if (DeviceIoControl(handle, IOCTL_DISK_GET_DRIVE_LAYOUT, NULL, + 0, (BYTE*)drive_layout, buf_size, &i, NULL)) + break; + err = GetLastError(); + free(drive_layout); + if (err != ERROR_INSUFFICIENT_BUFFER) { + ntfs_log_trace("GetDriveLayout failed.\n"); + errno = ntfs_w32error_to_errno(err); + return FALSE; + } + ntfs_log_debug("More than %u partitions.\n", part_count); + part_count <<= 1; + if (part_count > 512) { + ntfs_log_trace("GetDriveLayout failed: More than 512 " + "partitions?\n"); + errno = ENOBUFS; + return FALSE; + } + } while (1); + for (i = 0; i < drive_layout->PartitionCount; i++) { + if (drive_layout->PartitionEntry[i].PartitionNumber == + partition_id) { + *part_offset = drive_layout->PartitionEntry[i]. + StartingOffset.QuadPart; + *part_length = drive_layout->PartitionEntry[i]. + PartitionLength.QuadPart; + *hidden_sectors = drive_layout->PartitionEntry[i]. + HiddenSectors; + free(drive_layout); + return TRUE; + } + } + free(drive_layout); + errno = ENOENT; + return FALSE; +} + +/** + * ntfs_device_win32_open_partition - open a partition via win32 API + * @drive_id: drive to open + * @partition_id: partition to open + * @fd: win32 file device to return + * @flags: unix open status flags + * + * Return 0 if o.k. + * -1 if not, and errno set. + * + * When fails, fd contents may have not been preserved. + */ +static int ntfs_device_win32_open_partition(int drive_id, + unsigned int partition_id, win32_fd *fd, int flags) +{ + s64 part_start, part_length; + HANDLE handle; + int err, hidden_sectors; + char drive_name[MAX_PATH]; + + sprintf(drive_name, "\\\\.\\PhysicalDrive%d", drive_id); + /* Open the entire device without locking, ask questions later */ + if ((err = ntfs_device_win32_simple_open_file(drive_name, &handle, + flags, FALSE))) { + /* error */ + return err; + } + if (ntfs_device_win32_find_partition(handle, partition_id, &part_start, + &part_length, &hidden_sectors)) { + s64 tmp; + HANDLE vol_handle = ntfs_device_win32_open_volume_for_partition( + drive_id, part_start, part_length, flags); + /* Store the drive geometry. */ + ntfs_device_win32_getgeo(handle, fd); + fd->handle = handle; + fd->pos = 0; + fd->part_start = part_start; + fd->part_length = part_length; + fd->part_hidden_sectors = hidden_sectors; + tmp = ntfs_device_win32_getntfssize(vol_handle); + if (tmp > 0) + fd->geo_size = tmp; + else + fd->geo_size = fd->part_length; + if (vol_handle != INVALID_HANDLE_VALUE) { + if (((flags & O_RDWR) == O_RDWR) && + ntfs_device_win32_lock(vol_handle)) { + CloseHandle(vol_handle); + CloseHandle(handle); + return -1; + } + fd->vol_handle = vol_handle; + } else { + if ((flags & O_RDWR) == O_RDWR) { + /* Access if read-write, no volume found. */ + ntfs_log_trace("Partitions containing Spanned/" + "Mirrored volumes are not " + "supported in R/W status " + "yet.\n"); + CloseHandle(handle); + errno = EOPNOTSUPP; + return -1; + } + fd->vol_handle = INVALID_HANDLE_VALUE; + } + return 0; + } else { + ntfs_log_debug("Partition %u not found on drive %d.\n", + partition_id, drive_id); + CloseHandle(handle); + errno = ENODEV; + return -1; + } +} + +/** + * ntfs_device_win32_open - open a device + * @dev: a pointer to the NTFS_DEVICE to open + * @flags: unix open status flags + * + * @dev->d_name must hold the device name, the rest is ignored. + * Supported flags are O_RDONLY, O_WRONLY and O_RDWR. + * + * If name is in format "(hd[0-9],[0-9])" then open a partition. + * If name is in format "(hd[0-9])" then open a volume. + * Otherwise open a file. + */ +static int ntfs_device_win32_open(struct ntfs_device *dev, int flags) +{ + int drive_id = 0, numparams; + unsigned int part = 0; + char drive_char; + win32_fd fd; + int err; + + if (NDevOpen(dev)) { + errno = EBUSY; + return -1; + } + ntfs_device_win32_init_imports(); + numparams = sscanf(dev->d_name, "/dev/hd%c%u", &drive_char, &part); + drive_id = toupper(drive_char) - 'A'; + switch (numparams) { + case 0: + ntfs_log_debug("win32_open(%s) -> file.\n", dev->d_name); + err = ntfs_device_win32_open_file(dev->d_name, &fd, flags); + break; + case 1: + ntfs_log_debug("win32_open(%s) -> drive %d.\n", dev->d_name, + drive_id); + err = ntfs_device_win32_open_drive(drive_id, &fd, flags); + break; + case 2: + ntfs_log_debug("win32_open(%s) -> drive %d, part %u.\n", + dev->d_name, drive_id, part); + err = ntfs_device_win32_open_partition(drive_id, part, &fd, + flags); + break; + default: + ntfs_log_debug("win32_open(%s) -> unknwon file format.\n", + dev->d_name); + err = -1; + } + if (err) + return err; + ntfs_log_debug("win32_open(%s) -> %p, offset 0x%llx.\n", dev->d_name, + dev, fd.part_start); + /* Setup our read-only flag. */ + if ((flags & O_RDWR) != O_RDWR) + NDevSetReadOnly(dev); + dev->d_private = malloc(sizeof(win32_fd)); + memcpy(dev->d_private, &fd, sizeof(win32_fd)); + NDevSetOpen(dev); + NDevClearDirty(dev); + return 0; +} + +/** + * ntfs_device_win32_seek - change current logical file position + * @dev: ntfs device obtained via ->open + * @offset: required offset from the whence anchor + * @whence: whence anchor specifying what @offset is relative to + * + * Return the new position on the volume on success and -1 on error with errno + * set to the error code. + * + * @whence may be one of the following: + * SEEK_SET - Offset is relative to file start. + * SEEK_CUR - Offset is relative to current position. + * SEEK_END - Offset is relative to end of file. + */ +static s64 ntfs_device_win32_seek(struct ntfs_device *dev, s64 offset, + int whence) +{ + s64 abs_ofs; + win32_fd *fd = (win32_fd *)dev->d_private; + + ntfs_log_trace("seek offset = 0x%llx, whence = %d.\n", offset, whence); + switch (whence) { + case SEEK_SET: + abs_ofs = offset; + break; + case SEEK_CUR: + abs_ofs = fd->pos + offset; + break; + case SEEK_END: + /* End of partition != end of disk. */ + if (fd->part_length == -1) { + ntfs_log_trace("Position relative to end of disk not " + "implemented.\n"); + errno = EOPNOTSUPP; + return -1; + } + abs_ofs = fd->part_length + offset; + break; + default: + ntfs_log_trace("Wrong mode %d.\n", whence); + errno = EINVAL; + return -1; + } + if (abs_ofs < 0 || abs_ofs > fd->part_length) { + ntfs_log_trace("Seeking outsize seekable area.\n"); + errno = EINVAL; + return -1; + } + fd->pos = abs_ofs; + return abs_ofs; +} + +/** + * ntfs_device_win32_pio - positioned low level i/o + * @fd: win32 device descriptor obtained via ->open + * @pos: at which position to do i/o from/to + * @count: how many bytes should be transfered + * @b: source/destination buffer + * @write: TRUE if write transfer and FALSE if read transfer + * + * On success returns the number of bytes transfered (can be < @count) and on + * error returns -1 and errno set. Transfer starts from position @pos on @fd. + * + * Notes: + * - @pos, @buf, and @count must be aligned to NTFS_BLOCK_SIZE. + * - When dealing with volumes, a single call must not span both volume + * and disk extents. + * - Does not use/set @fd->pos. + */ +static s64 ntfs_device_win32_pio(win32_fd *fd, const s64 pos, + const s64 count, void *b, const BOOL write) +{ + LARGE_INTEGER li; + HANDLE handle; + DWORD bt; + BOOL res; + + ntfs_log_trace("pos = 0x%llx, count = 0x%llx, direction = %s.\n", + (long long)pos, (long long)count, write ? "write" : + "read"); + li.QuadPart = pos; + if (fd->vol_handle != INVALID_HANDLE_VALUE && pos < fd->geo_size) { + ntfs_log_debug("Transfering via vol_handle.\n"); + handle = fd->vol_handle; + } else { + ntfs_log_debug("Transfering via handle.\n"); + handle = fd->handle; + li.QuadPart += fd->part_start; + } + if (!fnSetFilePointerEx(handle, li, NULL, FILE_BEGIN)) { + errno = ntfs_w32error_to_errno(GetLastError()); + ntfs_log_trace("SetFilePointer failed.\n"); + return -1; + } + if (write) + res = WriteFile(handle, b, count, &bt, NULL); + else + res = ReadFile(handle, b, count, &bt, NULL); + if (!res) { + errno = ntfs_w32error_to_errno(GetLastError()); + ntfs_log_trace("%sFile() failed.\n", write ? "Write" : "Read"); + return -1; + } + return bt; +} + +/** + * ntfs_device_win32_pread_simple - positioned simple read + * @fd: win32 device descriptor obtained via ->open + * @pos: at which position to read from + * @count: how many bytes should be read + * @b: a pointer to where to put the contents + * + * On success returns the number of bytes read (can be < @count) and on error + * returns -1 and errno set. Read starts from position @pos. + * + * Notes: + * - @pos, @buf, and @count must be aligned to NTFS_BLOCK_SIZE. + * - When dealing with volumes, a single call must not span both volume + * and disk extents. + * - Does not use/set @fd->pos. + */ +static inline s64 ntfs_device_win32_pread_simple(win32_fd *fd, const s64 pos, + const s64 count, void *b) +{ + return ntfs_device_win32_pio(fd, pos, count, b, FALSE); +} + +/** + * ntfs_device_win32_read - read bytes from an ntfs device + * @dev: ntfs device obtained via ->open + * @b: pointer to where to put the contents + * @count: how many bytes should be read + * + * On success returns the number of bytes actually read (can be < @count). + * On error returns -1 with errno set. + */ +static s64 ntfs_device_win32_read(struct ntfs_device *dev, void *b, s64 count) +{ + s64 old_pos, to_read, i, br = 0; + win32_fd *fd = (win32_fd *)dev->d_private; + BYTE *alignedbuffer; + int old_ofs, ofs; + + old_pos = fd->pos; + old_ofs = ofs = old_pos & (NTFS_BLOCK_SIZE - 1); + to_read = (ofs + count + NTFS_BLOCK_SIZE - 1) & + ~(s64)(NTFS_BLOCK_SIZE - 1); + /* Impose maximum of 2GB to be on the safe side. */ + if (to_read > 0x80000000) { + int delta = to_read - count; + to_read = 0x80000000; + count = to_read - delta; + } + ntfs_log_trace("fd = %p, b = %p, count = 0x%llx, pos = 0x%llx, " + "ofs = %i, to_read = 0x%llx.\n", fd, b, + (long long)count, (long long)old_pos, ofs, + (long long)to_read); + if (!((unsigned long)b & (NTFS_BLOCK_SIZE - 1)) && !old_ofs && + !(count & (NTFS_BLOCK_SIZE - 1))) + alignedbuffer = b; + else { + alignedbuffer = (BYTE *)VirtualAlloc(NULL, to_read, MEM_COMMIT, + PAGE_READWRITE); + if (!alignedbuffer) { + errno = ntfs_w32error_to_errno(GetLastError()); + ntfs_log_trace("VirtualAlloc failed for read.\n"); + return -1; + } + } + if (fd->vol_handle != INVALID_HANDLE_VALUE && old_pos < fd->geo_size) { + s64 vol_to_read = fd->geo_size - old_pos; + if (count > vol_to_read) { + br = ntfs_device_win32_pread_simple(fd, + old_pos & ~(s64)(NTFS_BLOCK_SIZE - 1), + ofs + vol_to_read, alignedbuffer); + if (br == -1) + goto read_error; + to_read -= br; + if (br < ofs) { + br = 0; + goto read_partial; + } + br -= ofs; + fd->pos += br; + ofs = fd->pos & (NTFS_BLOCK_SIZE - 1); + if (br != vol_to_read) + goto read_partial; + } + } + i = ntfs_device_win32_pread_simple(fd, + fd->pos & ~(s64)(NTFS_BLOCK_SIZE - 1), to_read, + alignedbuffer + br); + if (i == -1) { + if (br) + goto read_partial; + goto read_error; + } + if (i < ofs) + goto read_partial; + i -= ofs; + br += i; + if (br > count) + br = count; + fd->pos = old_pos + br; +read_partial: + if (alignedbuffer != b) { + memcpy((void*)b, alignedbuffer + old_ofs, br); + VirtualFree(alignedbuffer, 0, MEM_RELEASE); + } + return br; +read_error: + if (alignedbuffer != b) + VirtualFree(alignedbuffer, 0, MEM_RELEASE); + return -1; +} + +/** + * ntfs_device_win32_close - close an open ntfs deivce + * @dev: ntfs device obtained via ->open + * + * Return 0 if o.k. + * -1 if not, and errno set. Note if error fd->vol_handle is trashed. + */ +static int ntfs_device_win32_close(struct ntfs_device *dev) +{ + win32_fd *fd = (win32_fd *)dev->d_private; + BOOL rvl; + + ntfs_log_trace("Closing device %p.\n", dev); + if (!NDevOpen(dev)) { + errno = EBADF; + return -1; + } + if (fd->vol_handle != INVALID_HANDLE_VALUE) { + if (!NDevReadOnly(dev)) { + ntfs_device_win32_dismount(fd->vol_handle); + ntfs_device_win32_unlock(fd->vol_handle); + } + if (!CloseHandle(fd->vol_handle)) + ntfs_log_trace("CloseHandle() failed for volume.\n"); + } + rvl = CloseHandle(fd->handle); + free(fd); + if (!rvl) { + errno = ntfs_w32error_to_errno(GetLastError()); + ntfs_log_trace("CloseHandle() failed.\n"); + return -1; + } + return 0; +} + +/** + * ntfs_device_win32_sync - flush write buffers to disk + * @dev: ntfs device obtained via ->open + * + * Return 0 if o.k. + * -1 if not, and errno set. + * + * Note: Volume syncing works differently in windows. + * Disk cannot be synced in windows. + */ +static int ntfs_device_win32_sync(struct ntfs_device *dev) +{ + int err = 0; + BOOL to_clear = TRUE; + + if (!NDevReadOnly(dev) && NDevDirty(dev)) { + win32_fd *fd = (win32_fd *)dev->d_private; + + if ((fd->vol_handle != INVALID_HANDLE_VALUE) && + !FlushFileBuffers(fd->vol_handle)) { + to_clear = FALSE; + err = ntfs_w32error_to_errno(GetLastError()); + } + if (!FlushFileBuffers(fd->handle)) { + to_clear = FALSE; + if (!err) + err = ntfs_w32error_to_errno(GetLastError()); + } + if (!to_clear) { + ntfs_log_trace("Could not sync.\n"); + errno = err; + return -1; + } + NDevClearDirty(dev); + } + return 0; +} + +/** + * ntfs_device_win32_pwrite_simple - positioned simple write + * @fd: win32 device descriptor obtained via ->open + * @pos: at which position to write to + * @count: how many bytes should be written + * @b: a pointer to the data to write + * + * On success returns the number of bytes written and on error returns -1 and + * errno set. Write starts from position @pos. + * + * Notes: + * - @pos, @buf, and @count must be aligned to NTFS_BLOCK_SIZE. + * - When dealing with volumes, a single call must not span both volume + * and disk extents. + * - Does not use/set @fd->pos. + */ +static inline s64 ntfs_device_win32_pwrite_simple(win32_fd *fd, const s64 pos, + const s64 count, const void *b) +{ + return ntfs_device_win32_pio(fd, pos, count, (void *)b, TRUE); +} + +/** + * ntfs_device_win32_write - write bytes to an ntfs device + * @dev: ntfs device obtained via ->open + * @b: pointer to the data to write + * @count: how many bytes should be written + * + * On success returns the number of bytes actually written. + * On error returns -1 with errno set. + */ +static s64 ntfs_device_win32_write(struct ntfs_device *dev, const void *b, + s64 count) +{ + s64 old_pos, to_write, i, bw = 0; + win32_fd *fd = (win32_fd *)dev->d_private; + BYTE *alignedbuffer; + int old_ofs, ofs; + + old_pos = fd->pos; + old_ofs = ofs = old_pos & (NTFS_BLOCK_SIZE - 1); + to_write = (ofs + count + NTFS_BLOCK_SIZE - 1) & + ~(s64)(NTFS_BLOCK_SIZE - 1); + /* Impose maximum of 2GB to be on the safe side. */ + if (to_write > 0x80000000) { + int delta = to_write - count; + to_write = 0x80000000; + count = to_write - delta; + } + ntfs_log_trace("fd = %p, b = %p, count = 0x%llx, pos = 0x%llx, " + "ofs = %i, to_write = 0x%llx.\n", fd, b, + (long long)count, (long long)old_pos, ofs, + (long long)to_write); + if (NDevReadOnly(dev)) { + ntfs_log_trace("Can't write on a R/O device.\n"); + errno = EROFS; + return -1; + } + if (!count) + return 0; + NDevSetDirty(dev); + if (!((unsigned long)b & (NTFS_BLOCK_SIZE - 1)) && !old_ofs && + !(count & (NTFS_BLOCK_SIZE - 1))) + alignedbuffer = (BYTE *)b; + else { + s64 end; + + alignedbuffer = (BYTE *)VirtualAlloc(NULL, to_write, + MEM_COMMIT, PAGE_READWRITE); + if (!alignedbuffer) { + errno = ntfs_w32error_to_errno(GetLastError()); + ntfs_log_trace("VirtualAlloc failed for write.\n"); + return -1; + } + /* Read first sector if start of write not sector aligned. */ + if (ofs) { + i = ntfs_device_win32_pread_simple(fd, + old_pos & ~(s64)(NTFS_BLOCK_SIZE - 1), + NTFS_BLOCK_SIZE, alignedbuffer); + if (i != NTFS_BLOCK_SIZE) { + if (i >= 0) + errno = EIO; + goto write_error; + } + } + /* + * Read last sector if end of write not sector aligned and last + * sector is either not the same as the first sector or it is + * the same as the first sector but this has not been read in + * yet, i.e. the start of the write is sector aligned. + */ + end = old_pos + count; + if ((end & (NTFS_BLOCK_SIZE - 1)) && + ((to_write > NTFS_BLOCK_SIZE) || !ofs)) { + i = ntfs_device_win32_pread_simple(fd, + end & ~(s64)(NTFS_BLOCK_SIZE - 1), + NTFS_BLOCK_SIZE, alignedbuffer + + to_write - NTFS_BLOCK_SIZE); + if (i != NTFS_BLOCK_SIZE) { + if (i >= 0) + errno = EIO; + goto write_error; + } + } + /* Copy the data to be written into @alignedbuffer. */ + memcpy(alignedbuffer + ofs, b, count); + } + if (fd->vol_handle != INVALID_HANDLE_VALUE && old_pos < fd->geo_size) { + s64 vol_to_write = fd->geo_size - old_pos; + if (count > vol_to_write) { + bw = ntfs_device_win32_pwrite_simple(fd, + old_pos & ~(s64)(NTFS_BLOCK_SIZE - 1), + ofs + vol_to_write, alignedbuffer); + if (bw == -1) + goto write_error; + to_write -= bw; + if (bw < ofs) { + bw = 0; + goto write_partial; + } + bw -= ofs; + fd->pos += bw; + ofs = fd->pos & (NTFS_BLOCK_SIZE - 1); + if (bw != vol_to_write) + goto write_partial; + } + } + i = ntfs_device_win32_pwrite_simple(fd, + fd->pos & ~(s64)(NTFS_BLOCK_SIZE - 1), to_write, + alignedbuffer + bw); + if (i == -1) { + if (bw) + goto write_partial; + goto write_error; + } + if (i < ofs) + goto write_partial; + i -= ofs; + bw += i; + if (bw > count) + bw = count; + fd->pos = old_pos + bw; +write_partial: + if (alignedbuffer != b) + VirtualFree(alignedbuffer, 0, MEM_RELEASE); + return bw; +write_error: + bw = -1; + goto write_partial; +} + +/** + * ntfs_device_win32_stat - get a unix-like stat structure for an ntfs device + * @dev: ntfs device obtained via ->open + * @buf: pointer to the stat structure to fill + * + * Note: Only st_mode, st_size, and st_blocks are filled. + * + * Return 0 if o.k. + * -1 if not and errno set. in this case handle is trashed. + */ +static int ntfs_device_win32_stat(struct ntfs_device *dev, struct stat *buf) +{ + win32_fd *fd = (win32_fd *)dev->d_private; + mode_t st_mode; + + switch (GetFileType(fd->handle)) { + case FILE_TYPE_CHAR: + st_mode = S_IFCHR; + break; + case FILE_TYPE_DISK: + st_mode = S_IFBLK; + break; + case FILE_TYPE_PIPE: + st_mode = S_IFIFO; + break; + default: + st_mode = 0; + } + memset(buf, 0, sizeof(struct stat)); + buf->st_mode = st_mode; + buf->st_size = fd->part_length; + if (buf->st_size != -1) + buf->st_blocks = buf->st_size >> 9; + else + buf->st_size = 0; + return 0; +} + +/** + * ntfs_win32_hdio_getgeo - get drive geometry + * @dev: ntfs device obtained via ->open + * @argp: pointer to where to put the output + * + * Note: Works on windows NT/2k/XP only. + * + * Return 0 if o.k. + * -1 if not, and errno set. Note if error fd->handle is trashed. + */ +static __inline__ int ntfs_win32_hdio_getgeo(struct ntfs_device *dev, + struct hd_geometry *argp) +{ + win32_fd *fd = (win32_fd *)dev->d_private; + + argp->heads = fd->geo_heads; + argp->sectors = fd->geo_sectors; + argp->cylinders = fd->geo_cylinders; + argp->start = fd->part_hidden_sectors; + return 0; +} + +/** + * ntfs_win32_blksszget - get block device sector size + * @dev: ntfs device obtained via ->open + * @argp: pointer to where to put the output + * + * Note: Works on windows NT/2k/XP only. + * + * Return 0 if o.k. + * -1 if not, and errno set. Note if error fd->handle is trashed. + */ +static __inline__ int ntfs_win32_blksszget(struct ntfs_device *dev,int *argp) +{ + win32_fd *fd = (win32_fd *)dev->d_private; + DWORD bytesReturned; + DISK_GEOMETRY dg; + + if (DeviceIoControl(fd->handle, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, + &dg, sizeof(DISK_GEOMETRY), &bytesReturned, NULL)) { + /* success */ + *argp = dg.BytesPerSector; + return 0; + } + errno = ntfs_w32error_to_errno(GetLastError()); + ntfs_log_trace("GET_DRIVE_GEOMETRY failed.\n"); + return -1; +} + +static int ntfs_device_win32_ioctl(struct ntfs_device *dev, int request, + void *argp) +{ + win32_fd *fd = (win32_fd *)dev->d_private; + + ntfs_log_trace("win32_ioctl(%d) called.\n", request); + switch (request) { +#if defined(BLKGETSIZE) + case BLKGETSIZE: + ntfs_log_debug("BLKGETSIZE detected.\n"); + if (fd->part_length >= 0) { + *(int *)argp = (int)(fd->part_length / 512); + return 0; + } + errno = EOPNOTSUPP; + return -1; +#endif +#if defined(BLKGETSIZE64) + case BLKGETSIZE64: + ntfs_log_debug("BLKGETSIZE64 detected.\n"); + if (fd->part_length >= 0) { + *(s64 *)argp = fd->part_length; + return 0; + } + errno = EOPNOTSUPP; + return -1; +#endif +#ifdef HDIO_GETGEO + case HDIO_GETGEO: + ntfs_log_debug("HDIO_GETGEO detected.\n"); + return ntfs_win32_hdio_getgeo(dev, (struct hd_geometry *)argp); +#endif +#ifdef BLKSSZGET + case BLKSSZGET: + ntfs_log_debug("BLKSSZGET detected.\n"); + return ntfs_win32_blksszget(dev, (int *)argp); +#endif +#ifdef BLKBSZSET + case BLKBSZSET: + ntfs_log_debug("BLKBSZSET detected.\n"); + /* Nothing to do on Windows. */ + return 0; +#endif + default: + ntfs_log_debug("unimplemented ioctl %d.\n", request); + errno = EOPNOTSUPP; + return -1; + } +} + +static s64 ntfs_device_win32_pread(struct ntfs_device *dev, void *b, + s64 count, s64 offset) +{ + return ntfs_pread(dev, offset, count, b); +} + +static s64 ntfs_device_win32_pwrite(struct ntfs_device *dev, const void *b, + s64 count, s64 offset) +{ + return ntfs_pwrite(dev, offset, count, b); +} + +struct ntfs_device_operations ntfs_device_win32_io_ops = { + .open = ntfs_device_win32_open, + .close = ntfs_device_win32_close, + .seek = ntfs_device_win32_seek, + .read = ntfs_device_win32_read, + .write = ntfs_device_win32_write, + .pread = ntfs_device_win32_pread, + .pwrite = ntfs_device_win32_pwrite, + .sync = ntfs_device_win32_sync, + .stat = ntfs_device_win32_stat, + .ioctl = ntfs_device_win32_ioctl +}; diff --git a/libtool b/libtool new file mode 100755 index 0000000..d9bbcad --- a/dev/null +++ b/libtool @@ -0,0 +1,7621 @@ +#! /bin/bash + +# libtoolT - Provide generalized library-building support services. +# Generated automatically by (GNU ntfs-3g 2010.5.16) +# NOTE: Changes made to this file will be lost: look at ltmain.sh. +# +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 +# Free Software Foundation, Inc. +# +# This file is part of GNU Libtool: +# Originally by Gordon Matzigkeit , 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 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# 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. + +# A sed program that does not truncate output. +SED="/bin/sed" + +# Sed that helps us avoid accidentally triggering echo(1) options like -n. +Xsed="/bin/sed -e 1s/^X//" + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +# The names of the tagged configurations supported by this script. +available_tags=" CXX" + +# ### BEGIN LIBTOOL CONFIG + +# Libtool was configured on host announce: + +# Shell to use when invoking shell scripts. +SHELL="/bin/bash" + +# Whether or not to build shared libraries. +build_libtool_libs=yes + +# Whether or not to build static libraries. +build_old_libs=yes + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=no + +# Whether or not to disallow shared libs when runtime libs are static +allow_libtool_libs_with_static_runtimes=no + +# Whether or not to optimize for fast installation. +fast_install=yes + +# The host system. +host_alias=arc-linux-uclibc +host=arc-unknown-linux-uclibc +host_os=linux-uclibc + +# The build system. +build_alias= +build=i686-pc-linux-gnu +build_os=linux-gnu + +# An echo program that does not interpret backslashes. +echo="echo" + +# The archiver. +AR="arc-linux-uclibc-ar" +AR_FLAGS="cru" + +# A C compiler. +LTCC="arc-linux-uclibc-gcc" + +# LTCC compiler flags. +LTCFLAGS="-mA7 -g" + +# A language-specific compiler. +CC="arc-linux-uclibc-gcc" + +# Is the compiler the GNU C compiler? +with_gcc=yes + +# An ERE matcher. +EGREP="/bin/grep -E" + +# The linker used to build libraries. +LD="/opt/gnutools/arc2.3-p0/uclibc-4.2.1/arc-linux-uclibc/bin/ld" + +# Whether we need hard or soft links. +LN_S="ln -s" + +# A BSD-compatible nm program. +NM="/opt/gnutools/arc2.3-p0/uclibc-4.2.1/bin/arc-linux-uclibc-nm -B" + +# A symbol stripping program +STRIP="arc-linux-uclibc-strip" + +# Used to examine libraries when file_magic_cmd begins "file" +MAGIC_CMD=file + +# Used on cygwin: DLL creation program. +DLLTOOL="dlltool" + +# Used on cygwin: object dumper. +OBJDUMP="objdump" + +# Used on cygwin: assembler. +AS="as" + +# The name of the directory that contains temporary libtool files. +objdir=.libs + +# How to create reloadable object files. +reload_flag=" -r" +reload_cmds="\$LD\$reload_flag -o \$output\$reload_objs" + +# How to pass a linker flag through the compiler. +wl="-Wl," + +# Object file suffix (normally "o"). +objext="o" + +# Old archive suffix (normally "a"). +libext="a" + +# Shared library suffix (normally ".so"). +shrext_cmds='.so' + +# Executable file suffix (normally ""). +exeext="" + +# Additional compiler flags for building library objects. +pic_flag=" -fPIC -DPIC" +pic_mode=default + +# What is the maximum length of a command? +max_cmd_len=805306365 + +# Does compiler simultaneously support -c and -o options? +compiler_c_o="yes" + +# Must we lock files when doing compilation? +need_locks="no" + +# Do we need the lib prefix for modules? +need_lib_prefix=no + +# Do we need a version for libraries? +need_version=no + +# Whether dlopen is supported. +dlopen_support=unknown + +# Whether dlopen of programs is supported. +dlopen_self=unknown + +# Whether dlopen of statically linked programs is supported. +dlopen_self_static=unknown + +# Compiler flag to prevent dynamic linking. +link_static_flag="-static" + +# Compiler flag to turn off builtin functions. +no_builtin_flag=" -fno-builtin" + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec="\${wl}--export-dynamic" + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec="\${wl}--whole-archive\$convenience \${wl}--no-whole-archive" + +# Compiler flag to generate thread-safe objects. +thread_safe_flag_spec="" + +# Library versioning type. +version_type=linux + +# Format of library name prefix. +libname_spec="lib\$name" + +# List of archive names. First name is the real one, the rest are links. +# The last name is the one that the linker finds with -lNAME. +library_names_spec="\${libname}\${release}\${shared_ext}\$versuffix \${libname}\${release}\${shared_ext}\$major \$libname\${shared_ext}" + +# The coded name of the library, if different from the real name. +soname_spec="\${libname}\${release}\${shared_ext}\$major" + +# Commands used to build and install an old-style archive. +RANLIB="arc-linux-uclibc-ranlib" +old_archive_cmds="\$AR \$AR_FLAGS \$oldlib\$oldobjs~\$RANLIB \$oldlib" +old_postinstall_cmds="chmod 644 \$oldlib~\$RANLIB \$oldlib" +old_postuninstall_cmds="" + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds="" + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds="" + +# Commands used to build and install a shared archive. +archive_cmds="\$CC -shared \$libobjs \$deplibs \$compiler_flags \${wl}-soname \$wl\$soname -o \$lib" +archive_expsym_cmds="\$echo \\\"{ global:\\\" > \$output_objdir/\$libname.ver~ + cat \$export_symbols | sed -e \\\"s/\\\\(.*\\\\)/\\\\1;/\\\" >> \$output_objdir/\$libname.ver~ + \$echo \\\"local: *; };\\\" >> \$output_objdir/\$libname.ver~ + \$CC -shared \$libobjs \$deplibs \$compiler_flags \${wl}-soname \$wl\$soname \${wl}-version-script \${wl}\$output_objdir/\$libname.ver -o \$lib" +postinstall_cmds="" +postuninstall_cmds="" + +# Commands used to build a loadable module (assumed same as above if empty) +module_cmds="" +module_expsym_cmds="" + +# Commands to strip libraries. +old_striplib="arc-linux-uclibc-strip --strip-debug" +striplib="arc-linux-uclibc-strip --strip-unneeded" + +# Dependencies to place before the objects being linked to create a +# shared library. +predep_objects="" + +# Dependencies to place after the objects being linked to create a +# shared library. +postdep_objects="" + +# Dependencies to place before the objects being linked to create a +# shared library. +predeps="" + +# Dependencies to place after the objects being linked to create a +# shared library. +postdeps="" + +# The directories searched by this compiler when creating a shared +# library +compiler_lib_search_dirs="" + +# The library search path used internally by the compiler when linking +# a shared library. +compiler_lib_search_path="" + +# Method to check whether dependent libraries are shared objects. +deplibs_check_method="pass_all" + +# Command to use when deplibs_check_method == file_magic. +file_magic_cmd="\$MAGIC_CMD" + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag="" + +# Flag that forces no undefined symbols. +no_undefined_flag="" + +# Commands used to finish a libtool library installation in a directory. +finish_cmds="PATH=\\\"\\\$PATH:/sbin\\\" ldconfig -n \$libdir" + +# Same as above, but a single script fragment to be evaled but not shown. +finish_eval="" + +# Take the output of nm and produce a listing of raw symbols and C names. +global_symbol_pipe="sed -n -e 's/^.*[ ]\\([ABCDGIRSTW][ABCDGIRSTW]*\\)[ ][ ]*\\([_A-Za-z][_A-Za-z0-9]*\\)\$/\\1 \\2 \\2/p'" + +# Transform the output of nm in a proper C declaration +global_symbol_to_cdecl="sed -n -e 's/^. .* \\(.*\\)\$/extern int \\1;/p'" + +# Transform the output of nm in a C name address pair +global_symbol_to_c_name_address="sed -n -e 's/^: \\([^ ]*\\) \$/ {\\\"\\1\\\", (lt_ptr) 0},/p' -e 's/^[BCDEGRST] \\([^ ]*\\) \\([^ ]*\\)\$/ {\"\\2\", (lt_ptr) \\&\\2},/p'" + +# This is the shared library runtime path variable. +runpath_var=LD_RUN_PATH + +# This is the shared library path variable. +shlibpath_var=LD_LIBRARY_PATH + +# Is shlibpath searched before the hard-coded library search path? +shlibpath_overrides_runpath=no + +# How to hardcode a shared library path into an executable. +hardcode_action=immediate + +# Whether we should hardcode library paths into libraries. +hardcode_into_libs=yes + +# Flag to hardcode $libdir into a binary during linking. +# This must work even if $libdir does not exist. +hardcode_libdir_flag_spec="\${wl}--rpath \${wl}\$libdir" + +# If ld is used when linking, flag to hardcode $libdir into +# a binary during linking. This must work even if $libdir does +# not exist. +hardcode_libdir_flag_spec_ld="" + +# Whether we need a single -rpath flag with a separated argument. +hardcode_libdir_separator="" + +# Set to yes if using DIR/libNAME during linking hardcodes DIR into the +# resulting binary. +hardcode_direct=no + +# Set to yes if using the -LDIR flag during linking hardcodes DIR into the +# resulting binary. +hardcode_minus_L=no + +# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into +# the resulting binary. +hardcode_shlibpath_var=unsupported + +# Set to yes if building a shared library automatically hardcodes DIR into the library +# and all subsequent libraries and executables linked against it. +hardcode_automatic=no + +# Variables whose values should be saved in libtool wrapper scripts and +# restored at relink time. +variables_saved_for_relink="PATH LD_LIBRARY_PATH LD_RUN_PATH GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=unknown + +# Compile-time system search path for libraries +sys_lib_search_path_spec="/opt/gnutools/arc2.3-p0/uclibc-4.2.1/lib/gcc/arc-linux-uclibc/4.2.1 /opt/gnutools/arc2.3-p0/uclibc-4.2.1/arc-linux-uclibc/lib" + +# Run-time system search path for libraries +sys_lib_dlsearch_path_spec="/lib /usr/lib /lib/i486-linux-gnu /usr/lib/i486-linux-gnu /usr/lib/alsa-lib /usr/local/lib " + +# Fix the shell variable $srcfile for the compiler. +fix_srcfile_path="" + +# Set to yes if exported symbols are required. +always_export_symbols=no + +# The commands to list exported symbols. +export_symbols_cmds="\$NM \$libobjs \$convenience | \$global_symbol_pipe | \$SED 's/.* //' | sort | uniq > \$export_symbols" + +# The commands to extract the exported symbol list from a shared archive. +extract_expsyms_cmds="" + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms="_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*" + +# Symbols that must always be exported. +include_expsyms="" + +# ### END LIBTOOL CONFIG + +# ltmain.sh - Provide generalized library-building support services. +# NOTE: Changing this file will not affect anything until you rerun configure. +# +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006, +# 2007, 2008 Free Software Foundation, Inc. +# Originally by Gordon Matzigkeit , 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 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# 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. + +basename="s,^.*/,,g" + +# Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh +# is ksh but when the shell is invoked as "sh" and the current value of +# the _XPG environment variable is not equal to 1 (one), the special +# positional parameter $0, within a function call, is the name of the +# function. +progpath="$0" + +# The name of this program: +progname=`echo "$progpath" | $SED $basename` +modename="$progname" + +# Global variables: +EXIT_SUCCESS=0 +EXIT_FAILURE=1 + +PROGRAM=ltmain.sh +PACKAGE=libtool +VERSION=1.5.26 +TIMESTAMP=" (1.1220.2.492 2008/01/30 06:40:56)" + +# Be Bourne compatible (taken from Autoconf:_AS_BOURNE_COMPATIBLE). +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs 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 +BIN_SH=xpg4; export BIN_SH # for Tru64 +DUALCASE=1; export DUALCASE # for MKS sh + +# Check that we have a working $echo. +if test "X$1" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift +elif test "X$1" = X--fallback-echo; then + # Avoid inline document here, it may be left over + : +elif test "X`($echo '\t') 2>/dev/null`" = 'X\t'; then + # Yippee, $echo works! + : +else + # Restart under the correct shell, and then maybe $echo will work. + exec $SHELL "$progpath" --no-reexec ${1+"$@"} +fi + +if test "X$1" = X--fallback-echo; then + # used as fallback echo + shift + cat <&2 + $echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2 + exit $EXIT_FAILURE +fi + +# Global variables. +mode=$default_mode +nonopt= +prev= +prevopt= +run= +show="$echo" +show_help= +execute_dlfiles= +duplicate_deps=no +preserve_args= +lo2o="s/\\.lo\$/.${objext}/" +o2lo="s/\\.${objext}\$/.lo/" +extracted_archives= +extracted_serial=0 + +##################################### +# Shell function definitions: +# This seems to be the best place for them + +# func_mktempdir [string] +# Make a temporary directory that won't clash with other running +# libtool processes, and avoids race conditions if possible. If +# given, STRING is the basename for that directory. +func_mktempdir () +{ + my_template="${TMPDIR-/tmp}/${1-$progname}" + + if test "$run" = ":"; then + # Return a directory name, but don't create it in dry-run mode + my_tmpdir="${my_template}-$$" + else + + # If mktemp works, use that first and foremost + my_tmpdir=`mktemp -d "${my_template}-XXXXXXXX" 2>/dev/null` + + if test ! -d "$my_tmpdir"; then + # Failing that, at least try and use $RANDOM to avoid a race + my_tmpdir="${my_template}-${RANDOM-0}$$" + + save_mktempdir_umask=`umask` + umask 0077 + $mkdir "$my_tmpdir" + umask $save_mktempdir_umask + fi + + # If we're not in dry-run mode, bomb out on failure + test -d "$my_tmpdir" || { + $echo "cannot create temporary directory \`$my_tmpdir'" 1>&2 + exit $EXIT_FAILURE + } + fi + + $echo "X$my_tmpdir" | $Xsed +} + + +# func_win32_libid arg +# return the library type of file 'arg' +# +# Need a lot of goo to handle *both* DLLs and import libs +# Has to be a shell function in order to 'eat' the argument +# that is supplied when $file_magic_command is called. +func_win32_libid () +{ + win32_libid_type="unknown" + win32_fileres=`file -L $1 2>/dev/null` + case $win32_fileres in + *ar\ archive\ import\ library*) # definitely import + win32_libid_type="x86 archive import" + ;; + *ar\ archive*) # could be an import, or static + if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null | \ + $EGREP -e 'file format pe-i386(.*architecture: i386)?' >/dev/null ; then + win32_nmres=`eval $NM -f posix -A $1 | \ + $SED -n -e '1,100{ + / I /{ + s,.*,import, + p + q + } + }'` + case $win32_nmres in + import*) win32_libid_type="x86 archive import";; + *) win32_libid_type="x86 archive static";; + esac + fi + ;; + *DLL*) + win32_libid_type="x86 DLL" + ;; + *executable*) # but shell scripts are "executable" too... + case $win32_fileres in + *MS\ Windows\ PE\ Intel*) + win32_libid_type="x86 DLL" + ;; + esac + ;; + esac + $echo $win32_libid_type +} + + +# func_infer_tag arg +# Infer tagged configuration to use if any are available and +# if one wasn't chosen via the "--tag" command line option. +# Only attempt this if the compiler in the base compile +# command doesn't match the default compiler. +# arg is usually of the form 'gcc ...' +func_infer_tag () +{ + if test -n "$available_tags" && test -z "$tagname"; then + CC_quoted= + for arg in $CC; do + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + CC_quoted="$CC_quoted $arg" + done + case $@ in + # Blanks in the command may have been stripped by the calling shell, + # but not from the CC environment variable when configure was run. + " $CC "* | "$CC "* | " `$echo $CC` "* | "`$echo $CC` "* | " $CC_quoted"* | "$CC_quoted "* | " `$echo $CC_quoted` "* | "`$echo $CC_quoted` "*) ;; + # Blanks at the start of $base_compile will cause this to fail + # if we don't check for them as well. + *) + for z in $available_tags; do + if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then + # Evaluate the configuration. + eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`" + CC_quoted= + for arg in $CC; do + # Double-quote args containing other shell metacharacters. + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + CC_quoted="$CC_quoted $arg" + done + case "$@ " in + " $CC "* | "$CC "* | " `$echo $CC` "* | "`$echo $CC` "* | " $CC_quoted"* | "$CC_quoted "* | " `$echo $CC_quoted` "* | "`$echo $CC_quoted` "*) + # The compiler in the base compile command matches + # the one in the tagged configuration. + # Assume this is the tagged configuration we want. + tagname=$z + break + ;; + esac + fi + done + # If $tagname still isn't set, then no tagged configuration + # was found and let the user know that the "--tag" command + # line option must be used. + if test -z "$tagname"; then + $echo "$modename: unable to infer tagged configuration" + $echo "$modename: specify a tag with \`--tag'" 1>&2 + exit $EXIT_FAILURE +# else +# $echo "$modename: using $tagname tagged configuration" + fi + ;; + esac + fi +} + + +# func_extract_an_archive dir oldlib +func_extract_an_archive () +{ + f_ex_an_ar_dir="$1"; shift + f_ex_an_ar_oldlib="$1" + + $show "(cd $f_ex_an_ar_dir && $AR x $f_ex_an_ar_oldlib)" + $run eval "(cd \$f_ex_an_ar_dir && $AR x \$f_ex_an_ar_oldlib)" || exit $? + if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then + : + else + $echo "$modename: ERROR: object name conflicts: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib" 1>&2 + exit $EXIT_FAILURE + fi +} + +# func_extract_archives gentop oldlib ... +func_extract_archives () +{ + my_gentop="$1"; shift + my_oldlibs=${1+"$@"} + my_oldobjs="" + my_xlib="" + my_xabs="" + my_xdir="" + my_status="" + + $show "${rm}r $my_gentop" + $run ${rm}r "$my_gentop" + $show "$mkdir $my_gentop" + $run $mkdir "$my_gentop" + my_status=$? + if test "$my_status" -ne 0 && test ! -d "$my_gentop"; then + exit $my_status + fi + + for my_xlib in $my_oldlibs; do + # Extract the objects. + case $my_xlib in + [\\/]* | [A-Za-z]:[\\/]*) my_xabs="$my_xlib" ;; + *) my_xabs=`pwd`"/$my_xlib" ;; + esac + my_xlib=`$echo "X$my_xlib" | $Xsed -e 's%^.*/%%'` + my_xlib_u=$my_xlib + while :; do + case " $extracted_archives " in + *" $my_xlib_u "*) + extracted_serial=`expr $extracted_serial + 1` + my_xlib_u=lt$extracted_serial-$my_xlib ;; + *) break ;; + esac + done + extracted_archives="$extracted_archives $my_xlib_u" + my_xdir="$my_gentop/$my_xlib_u" + + $show "${rm}r $my_xdir" + $run ${rm}r "$my_xdir" + $show "$mkdir $my_xdir" + $run $mkdir "$my_xdir" + exit_status=$? + if test "$exit_status" -ne 0 && test ! -d "$my_xdir"; then + exit $exit_status + fi + case $host in + *-darwin*) + $show "Extracting $my_xabs" + # Do not bother doing anything if just a dry run + if test -z "$run"; then + darwin_orig_dir=`pwd` + cd $my_xdir || exit $? + darwin_archive=$my_xabs + darwin_curdir=`pwd` + darwin_base_archive=`$echo "X$darwin_archive" | $Xsed -e 's%^.*/%%'` + darwin_arches=`lipo -info "$darwin_archive" 2>/dev/null | $EGREP Architectures 2>/dev/null` + if test -n "$darwin_arches"; then + darwin_arches=`echo "$darwin_arches" | $SED -e 's/.*are://'` + darwin_arch= + $show "$darwin_base_archive has multiple architectures $darwin_arches" + for darwin_arch in $darwin_arches ; do + mkdir -p "unfat-$$/${darwin_base_archive}-${darwin_arch}" + lipo -thin $darwin_arch -output "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" "${darwin_archive}" + cd "unfat-$$/${darwin_base_archive}-${darwin_arch}" + func_extract_an_archive "`pwd`" "${darwin_base_archive}" + cd "$darwin_curdir" + $rm "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" + done # $darwin_arches + ## Okay now we have a bunch of thin objects, gotta fatten them up :) + darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print| xargs basename | sort -u | $NL2SP` + darwin_file= + darwin_files= + for darwin_file in $darwin_filelist; do + darwin_files=`find unfat-$$ -name $darwin_file -print | $NL2SP` + lipo -create -output "$darwin_file" $darwin_files + done # $darwin_filelist + ${rm}r unfat-$$ + cd "$darwin_orig_dir" + else + cd "$darwin_orig_dir" + func_extract_an_archive "$my_xdir" "$my_xabs" + fi # $darwin_arches + fi # $run + ;; + *) + func_extract_an_archive "$my_xdir" "$my_xabs" + ;; + esac + my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | $NL2SP` + done + func_extract_archives_result="$my_oldobjs" +} +# End of Shell function definitions +##################################### + +# Darwin sucks +eval std_shrext=\"$shrext_cmds\" + +disable_libs=no + +# Parse our command line options once, thoroughly. +while test "$#" -gt 0 +do + arg="$1" + shift + + case $arg in + -*=*) optarg=`$echo "X$arg" | $Xsed -e 's/[-_a-zA-Z0-9]*=//'` ;; + *) optarg= ;; + esac + + # If the previous option needs an argument, assign it. + if test -n "$prev"; then + case $prev in + execute_dlfiles) + execute_dlfiles="$execute_dlfiles $arg" + ;; + tag) + tagname="$arg" + preserve_args="${preserve_args}=$arg" + + # Check whether tagname contains only valid characters + case $tagname in + *[!-_A-Za-z0-9,/]*) + $echo "$progname: invalid tag name: $tagname" 1>&2 + exit $EXIT_FAILURE + ;; + esac + + case $tagname in + CC) + # Don't test for the "default" C tag, as we know, it's there, but + # not specially marked. + ;; + *) + if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$" < "$progpath" > /dev/null; then + taglist="$taglist $tagname" + # Evaluate the configuration. + eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$tagname'$/,/^# ### END LIBTOOL TAG CONFIG: '$tagname'$/p' < $progpath`" + else + $echo "$progname: ignoring unknown tag $tagname" 1>&2 + fi + ;; + esac + ;; + *) + eval "$prev=\$arg" + ;; + esac + + prev= + prevopt= + continue + fi + + # Have we seen a non-optional argument yet? + case $arg in + --help) + show_help=yes + ;; + + --version) + echo "\ +$PROGRAM (GNU $PACKAGE) $VERSION$TIMESTAMP + +Copyright (C) 2008 Free Software Foundation, Inc. +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + exit $? + ;; + + --config) + ${SED} -e '1,/^# ### BEGIN LIBTOOL CONFIG/d' -e '/^# ### END LIBTOOL CONFIG/,$d' $progpath + # Now print the configurations for the tags. + for tagname in $taglist; do + ${SED} -n -e "/^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$/,/^# ### END LIBTOOL TAG CONFIG: $tagname$/p" < "$progpath" + done + exit $? + ;; + + --debug) + $echo "$progname: enabling shell trace mode" + set -x + preserve_args="$preserve_args $arg" + ;; + + --dry-run | -n) + run=: + ;; + + --features) + $echo "host: $host" + if test "$build_libtool_libs" = yes; then + $echo "enable shared libraries" + else + $echo "disable shared libraries" + fi + if test "$build_old_libs" = yes; then + $echo "enable static libraries" + else + $echo "disable static libraries" + fi + exit $? + ;; + + --finish) mode="finish" ;; + + --mode) prevopt="--mode" prev=mode ;; + --mode=*) mode="$optarg" ;; + + --preserve-dup-deps) duplicate_deps="yes" ;; + + --quiet | --silent) + show=: + preserve_args="$preserve_args $arg" + ;; + + --tag) + prevopt="--tag" + prev=tag + preserve_args="$preserve_args --tag" + ;; + --tag=*) + set tag "$optarg" ${1+"$@"} + shift + prev=tag + preserve_args="$preserve_args --tag" + ;; + + -dlopen) + prevopt="-dlopen" + prev=execute_dlfiles + ;; + + -*) + $echo "$modename: unrecognized option \`$arg'" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + ;; + + *) + nonopt="$arg" + break + ;; + esac +done + +if test -n "$prevopt"; then + $echo "$modename: option \`$prevopt' requires an argument" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE +fi + +case $disable_libs in +no) + ;; +shared) + build_libtool_libs=no + build_old_libs=yes + ;; +static) + build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac` + ;; +esac + +# If this variable is set in any of the actions, the command in it +# will be execed at the end. This prevents here-documents from being +# left over by shells. +exec_cmd= + +if test -z "$show_help"; then + + # Infer the operation mode. + if test -z "$mode"; then + $echo "*** Warning: inferring the mode of operation is deprecated." 1>&2 + $echo "*** Future versions of Libtool will require --mode=MODE be specified." 1>&2 + case $nonopt in + *cc | cc* | *++ | gcc* | *-gcc* | g++* | xlc*) + mode=link + for arg + do + case $arg in + -c) + mode=compile + break + ;; + esac + done + ;; + *db | *dbx | *strace | *truss) + mode=execute + ;; + *install*|cp|mv) + mode=install + ;; + *rm) + mode=uninstall + ;; + *) + # If we have no mode, but dlfiles were specified, then do execute mode. + test -n "$execute_dlfiles" && mode=execute + + # Just use the default operation mode. + if test -z "$mode"; then + if test -n "$nonopt"; then + $echo "$modename: warning: cannot infer operation mode from \`$nonopt'" 1>&2 + else + $echo "$modename: warning: cannot infer operation mode without MODE-ARGS" 1>&2 + fi + fi + ;; + esac + fi + + # Only execute mode is allowed to have -dlopen flags. + if test -n "$execute_dlfiles" && test "$mode" != execute; then + $echo "$modename: unrecognized option \`-dlopen'" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + # Change the help message to a mode-specific one. + generic_help="$help" + help="Try \`$modename --help --mode=$mode' for more information." + + # These modes are in order of execution frequency so that they run quickly. + case $mode in + # libtool compile mode + compile) + modename="$modename: compile" + # Get the compilation command and the source file. + base_compile= + srcfile="$nonopt" # always keep a non-empty value in "srcfile" + suppress_opt=yes + suppress_output= + arg_mode=normal + libobj= + later= + + for arg + do + case $arg_mode in + arg ) + # do not "continue". Instead, add this to base_compile + lastarg="$arg" + arg_mode=normal + ;; + + target ) + libobj="$arg" + arg_mode=normal + continue + ;; + + normal ) + # Accept any command-line options. + case $arg in + -o) + if test -n "$libobj" ; then + $echo "$modename: you cannot specify \`-o' more than once" 1>&2 + exit $EXIT_FAILURE + fi + arg_mode=target + continue + ;; + + -static | -prefer-pic | -prefer-non-pic) + later="$later $arg" + continue + ;; + + -no-suppress) + suppress_opt=no + continue + ;; + + -Xcompiler) + arg_mode=arg # the next one goes into the "base_compile" arg list + continue # The current "srcfile" will either be retained or + ;; # replaced later. I would guess that would be a bug. + + -Wc,*) + args=`$echo "X$arg" | $Xsed -e "s/^-Wc,//"` + lastarg= + save_ifs="$IFS"; IFS=',' + for arg in $args; do + IFS="$save_ifs" + + # Double-quote args containing other shell metacharacters. + # Many Bourne shells cannot handle close brackets correctly + # in scan sets, so we specify it separately. + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + lastarg="$lastarg $arg" + done + IFS="$save_ifs" + lastarg=`$echo "X$lastarg" | $Xsed -e "s/^ //"` + + # Add the arguments to base_compile. + base_compile="$base_compile $lastarg" + continue + ;; + + * ) + # Accept the current argument as the source file. + # The previous "srcfile" becomes the current argument. + # + lastarg="$srcfile" + srcfile="$arg" + ;; + esac # case $arg + ;; + esac # case $arg_mode + + # Aesthetically quote the previous argument. + lastarg=`$echo "X$lastarg" | $Xsed -e "$sed_quote_subst"` + + case $lastarg in + # Double-quote args containing other shell metacharacters. + # Many Bourne shells cannot handle close brackets correctly + # in scan sets, and some SunOS ksh mistreat backslash-escaping + # in scan sets (worked around with variable expansion), + # and furthermore cannot handle '|' '&' '(' ')' in scan sets + # at all, so we specify them separately. + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + lastarg="\"$lastarg\"" + ;; + esac + + base_compile="$base_compile $lastarg" + done # for arg + + case $arg_mode in + arg) + $echo "$modename: you must specify an argument for -Xcompile" + exit $EXIT_FAILURE + ;; + target) + $echo "$modename: you must specify a target with \`-o'" 1>&2 + exit $EXIT_FAILURE + ;; + *) + # Get the name of the library object. + [ -z "$libobj" ] && libobj=`$echo "X$srcfile" | $Xsed -e 's%^.*/%%'` + ;; + esac + + # Recognize several different file suffixes. + # If the user specifies -o file.o, it is replaced with file.lo + xform='[cCFSifmso]' + case $libobj in + *.ada) xform=ada ;; + *.adb) xform=adb ;; + *.ads) xform=ads ;; + *.asm) xform=asm ;; + *.c++) xform=c++ ;; + *.cc) xform=cc ;; + *.ii) xform=ii ;; + *.class) xform=class ;; + *.cpp) xform=cpp ;; + *.cxx) xform=cxx ;; + *.[fF][09]?) xform=[fF][09]. ;; + *.for) xform=for ;; + *.java) xform=java ;; + *.obj) xform=obj ;; + *.sx) xform=sx ;; + esac + + libobj=`$echo "X$libobj" | $Xsed -e "s/\.$xform$/.lo/"` + + case $libobj in + *.lo) obj=`$echo "X$libobj" | $Xsed -e "$lo2o"` ;; + *) + $echo "$modename: cannot determine name of library object from \`$libobj'" 1>&2 + exit $EXIT_FAILURE + ;; + esac + + func_infer_tag $base_compile + + for arg in $later; do + case $arg in + -static) + build_old_libs=yes + continue + ;; + + -prefer-pic) + pic_mode=yes + continue + ;; + + -prefer-non-pic) + pic_mode=no + continue + ;; + esac + done + + qlibobj=`$echo "X$libobj" | $Xsed -e "$sed_quote_subst"` + case $qlibobj in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + qlibobj="\"$qlibobj\"" ;; + esac + test "X$libobj" != "X$qlibobj" \ + && $echo "X$libobj" | grep '[]~#^*{};<>?"'"'"' &()|`$[]' \ + && $echo "$modename: libobj name \`$libobj' may not contain shell special characters." + objname=`$echo "X$obj" | $Xsed -e 's%^.*/%%'` + xdir=`$echo "X$obj" | $Xsed -e 's%/[^/]*$%%'` + if test "X$xdir" = "X$obj"; then + xdir= + else + xdir=$xdir/ + fi + lobj=${xdir}$objdir/$objname + + if test -z "$base_compile"; then + $echo "$modename: you must specify a compilation command" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + # Delete any leftover library objects. + if test "$build_old_libs" = yes; then + removelist="$obj $lobj $libobj ${libobj}T" + else + removelist="$lobj $libobj ${libobj}T" + fi + + $run $rm $removelist + trap "$run $rm $removelist; exit $EXIT_FAILURE" 1 2 15 + + # On Cygwin there's no "real" PIC flag so we must build both object types + case $host_os in + cygwin* | mingw* | pw32* | os2*) + pic_mode=default + ;; + esac + if test "$pic_mode" = no && test "$deplibs_check_method" != pass_all; then + # non-PIC code in shared libraries is not supported + pic_mode=default + fi + + # Calculate the filename of the output object if compiler does + # not support -o with -c + if test "$compiler_c_o" = no; then + output_obj=`$echo "X$srcfile" | $Xsed -e 's%^.*/%%' -e 's%\.[^.]*$%%'`.${objext} + lockfile="$output_obj.lock" + removelist="$removelist $output_obj $lockfile" + trap "$run $rm $removelist; exit $EXIT_FAILURE" 1 2 15 + else + output_obj= + need_locks=no + lockfile= + fi + + # Lock this critical section if it is needed + # We use this script file to make the link, it avoids creating a new file + if test "$need_locks" = yes; then + until $run ln "$progpath" "$lockfile" 2>/dev/null; do + $show "Waiting for $lockfile to be removed" + sleep 2 + done + elif test "$need_locks" = warn; then + if test -f "$lockfile"; then + $echo "\ +*** ERROR, $lockfile exists and contains: +`cat $lockfile 2>/dev/null` + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $run $rm $removelist + exit $EXIT_FAILURE + fi + $echo "$srcfile" > "$lockfile" + fi + + if test -n "$fix_srcfile_path"; then + eval srcfile=\"$fix_srcfile_path\" + fi + qsrcfile=`$echo "X$srcfile" | $Xsed -e "$sed_quote_subst"` + case $qsrcfile in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + qsrcfile="\"$qsrcfile\"" ;; + esac + + $run $rm "$libobj" "${libobj}T" + + # Create a libtool object file (analogous to a ".la" file), + # but don't create it if we're doing a dry run. + test -z "$run" && cat > ${libobj}T </dev/null`" != "X$srcfile"; then + $echo "\ +*** ERROR, $lockfile contains: +`cat $lockfile 2>/dev/null` + +but it should contain: +$srcfile + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $run $rm $removelist + exit $EXIT_FAILURE + fi + + # Just move the object if needed, then go on to compile the next one + if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then + $show "$mv $output_obj $lobj" + if $run $mv $output_obj $lobj; then : + else + error=$? + $run $rm $removelist + exit $error + fi + fi + + # Append the name of the PIC object to the libtool object file. + test -z "$run" && cat >> ${libobj}T <> ${libobj}T </dev/null`" != "X$srcfile"; then + $echo "\ +*** ERROR, $lockfile contains: +`cat $lockfile 2>/dev/null` + +but it should contain: +$srcfile + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $run $rm $removelist + exit $EXIT_FAILURE + fi + + # Just move the object if needed + if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then + $show "$mv $output_obj $obj" + if $run $mv $output_obj $obj; then : + else + error=$? + $run $rm $removelist + exit $error + fi + fi + + # Append the name of the non-PIC object the libtool object file. + # Only append if the libtool object file exists. + test -z "$run" && cat >> ${libobj}T <> ${libobj}T <&2 + fi + if test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + prefer_static_libs=yes + ;; + -static) + if test -z "$pic_flag" && test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + prefer_static_libs=built + ;; + -static-libtool-libs) + if test -z "$pic_flag" && test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + prefer_static_libs=yes + ;; + esac + build_libtool_libs=no + build_old_libs=yes + break + ;; + esac + done + + # See if our shared archives depend on static archives. + test -n "$old_archive_from_new_cmds" && build_old_libs=yes + + # Go through the arguments, transforming them on the way. + while test "$#" -gt 0; do + arg="$1" + shift + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + qarg=\"`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`\" ### testsuite: skip nested quoting test + ;; + *) qarg=$arg ;; + esac + libtool_args="$libtool_args $qarg" + + # If the previous option needs an argument, assign it. + if test -n "$prev"; then + case $prev in + output) + compile_command="$compile_command @OUTPUT@" + finalize_command="$finalize_command @OUTPUT@" + ;; + esac + + case $prev in + dlfiles|dlprefiles) + if test "$preload" = no; then + # Add the symbol object into the linking commands. + compile_command="$compile_command @SYMFILE@" + finalize_command="$finalize_command @SYMFILE@" + preload=yes + fi + case $arg in + *.la | *.lo) ;; # We handle these cases below. + force) + if test "$dlself" = no; then + dlself=needless + export_dynamic=yes + fi + prev= + continue + ;; + self) + if test "$prev" = dlprefiles; then + dlself=yes + elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then + dlself=yes + else + dlself=needless + export_dynamic=yes + fi + prev= + continue + ;; + *) + if test "$prev" = dlfiles; then + dlfiles="$dlfiles $arg" + else + dlprefiles="$dlprefiles $arg" + fi + prev= + continue + ;; + esac + ;; + expsyms) + export_symbols="$arg" + if test ! -f "$arg"; then + $echo "$modename: symbol file \`$arg' does not exist" + exit $EXIT_FAILURE + fi + prev= + continue + ;; + expsyms_regex) + export_symbols_regex="$arg" + prev= + continue + ;; + inst_prefix) + inst_prefix_dir="$arg" + prev= + continue + ;; + precious_regex) + precious_files_regex="$arg" + prev= + continue + ;; + release) + release="-$arg" + prev= + continue + ;; + objectlist) + if test -f "$arg"; then + save_arg=$arg + moreargs= + for fil in `cat $save_arg` + do +# moreargs="$moreargs $fil" + arg=$fil + # A libtool-controlled object. + + # Check to see that this really is a libtool object. + if (${SED} -e '2q' $arg | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + pic_object= + non_pic_object= + + # Read the .lo file + # If there is no directory component, then add one. + case $arg in + */* | *\\*) . $arg ;; + *) . ./$arg ;; + esac + + if test -z "$pic_object" || \ + test -z "$non_pic_object" || + test "$pic_object" = none && \ + test "$non_pic_object" = none; then + $echo "$modename: cannot find name of object for \`$arg'" 1>&2 + exit $EXIT_FAILURE + fi + + # Extract subdirectory from the argument. + xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'` + if test "X$xdir" = "X$arg"; then + xdir= + else + xdir="$xdir/" + fi + + if test "$pic_object" != none; then + # Prepend the subdirectory the object is found in. + pic_object="$xdir$pic_object" + + if test "$prev" = dlfiles; then + if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then + dlfiles="$dlfiles $pic_object" + prev= + continue + else + # If libtool objects are unsupported, then we need to preload. + prev=dlprefiles + fi + fi + + # CHECK ME: I think I busted this. -Ossama + if test "$prev" = dlprefiles; then + # Preload the old-style object. + dlprefiles="$dlprefiles $pic_object" + prev= + fi + + # A PIC object. + libobjs="$libobjs $pic_object" + arg="$pic_object" + fi + + # Non-PIC object. + if test "$non_pic_object" != none; then + # Prepend the subdirectory the object is found in. + non_pic_object="$xdir$non_pic_object" + + # A standard non-PIC object + non_pic_objects="$non_pic_objects $non_pic_object" + if test -z "$pic_object" || test "$pic_object" = none ; then + arg="$non_pic_object" + fi + else + # If the PIC object exists, use it instead. + # $xdir was prepended to $pic_object above. + non_pic_object="$pic_object" + non_pic_objects="$non_pic_objects $non_pic_object" + fi + else + # Only an error if not doing a dry-run. + if test -z "$run"; then + $echo "$modename: \`$arg' is not a valid libtool object" 1>&2 + exit $EXIT_FAILURE + else + # Dry-run case. + + # Extract subdirectory from the argument. + xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'` + if test "X$xdir" = "X$arg"; then + xdir= + else + xdir="$xdir/" + fi + + pic_object=`$echo "X${xdir}${objdir}/${arg}" | $Xsed -e "$lo2o"` + non_pic_object=`$echo "X${xdir}${arg}" | $Xsed -e "$lo2o"` + libobjs="$libobjs $pic_object" + non_pic_objects="$non_pic_objects $non_pic_object" + fi + fi + done + else + $echo "$modename: link input file \`$save_arg' does not exist" + exit $EXIT_FAILURE + fi + arg=$save_arg + prev= + continue + ;; + rpath | xrpath) + # We need an absolute path. + case $arg in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + $echo "$modename: only absolute run-paths are allowed" 1>&2 + exit $EXIT_FAILURE + ;; + esac + if test "$prev" = rpath; then + case "$rpath " in + *" $arg "*) ;; + *) rpath="$rpath $arg" ;; + esac + else + case "$xrpath " in + *" $arg "*) ;; + *) xrpath="$xrpath $arg" ;; + esac + fi + prev= + continue + ;; + xcompiler) + compiler_flags="$compiler_flags $qarg" + prev= + compile_command="$compile_command $qarg" + finalize_command="$finalize_command $qarg" + continue + ;; + xlinker) + linker_flags="$linker_flags $qarg" + compiler_flags="$compiler_flags $wl$qarg" + prev= + compile_command="$compile_command $wl$qarg" + finalize_command="$finalize_command $wl$qarg" + continue + ;; + xcclinker) + linker_flags="$linker_flags $qarg" + compiler_flags="$compiler_flags $qarg" + prev= + compile_command="$compile_command $qarg" + finalize_command="$finalize_command $qarg" + continue + ;; + shrext) + shrext_cmds="$arg" + prev= + continue + ;; + darwin_framework|darwin_framework_skip) + test "$prev" = "darwin_framework" && compiler_flags="$compiler_flags $arg" + compile_command="$compile_command $arg" + finalize_command="$finalize_command $arg" + prev= + continue + ;; + *) + eval "$prev=\"\$arg\"" + prev= + continue + ;; + esac + fi # test -n "$prev" + + prevarg="$arg" + + case $arg in + -all-static) + if test -n "$link_static_flag"; then + compile_command="$compile_command $link_static_flag" + finalize_command="$finalize_command $link_static_flag" + fi + continue + ;; + + -allow-undefined) + # FIXME: remove this flag sometime in the future. + $echo "$modename: \`-allow-undefined' is deprecated because it is the default" 1>&2 + continue + ;; + + -avoid-version) + avoid_version=yes + continue + ;; + + -dlopen) + prev=dlfiles + continue + ;; + + -dlpreopen) + prev=dlprefiles + continue + ;; + + -export-dynamic) + export_dynamic=yes + continue + ;; + + -export-symbols | -export-symbols-regex) + if test -n "$export_symbols" || test -n "$export_symbols_regex"; then + $echo "$modename: more than one -exported-symbols argument is not allowed" + exit $EXIT_FAILURE + fi + if test "X$arg" = "X-export-symbols"; then + prev=expsyms + else + prev=expsyms_regex + fi + continue + ;; + + -framework|-arch|-isysroot) + case " $CC " in + *" ${arg} ${1} "* | *" ${arg} ${1} "*) + prev=darwin_framework_skip ;; + *) compiler_flags="$compiler_flags $arg" + prev=darwin_framework ;; + esac + compile_command="$compile_command $arg" + finalize_command="$finalize_command $arg" + continue + ;; + + -inst-prefix-dir) + prev=inst_prefix + continue + ;; + + # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:* + # so, if we see these flags be careful not to treat them like -L + -L[A-Z][A-Z]*:*) + case $with_gcc/$host in + no/*-*-irix* | /*-*-irix*) + compile_command="$compile_command $arg" + finalize_command="$finalize_command $arg" + ;; + esac + continue + ;; + + -L*) + dir=`$echo "X$arg" | $Xsed -e 's/^-L//'` + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + absdir=`cd "$dir" && pwd` + if test -z "$absdir"; then + $echo "$modename: cannot determine absolute directory name of \`$dir'" 1>&2 + absdir="$dir" + notinst_path="$notinst_path $dir" + fi + dir="$absdir" + ;; + esac + case "$deplibs " in + *" -L$dir "*) ;; + *) + deplibs="$deplibs -L$dir" + lib_search_path="$lib_search_path $dir" + ;; + esac + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*) + testbindir=`$echo "X$dir" | $Xsed -e 's*/lib$*/bin*'` + case :$dllsearchpath: in + *":$dir:"*) ;; + *) dllsearchpath="$dllsearchpath:$dir";; + esac + case :$dllsearchpath: in + *":$testbindir:"*) ;; + *) dllsearchpath="$dllsearchpath:$testbindir";; + esac + ;; + esac + continue + ;; + + -l*) + if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos*) + # These systems don't actually have a C or math library (as such) + continue + ;; + *-*-os2*) + # These systems don't actually have a C library (as such) + test "X$arg" = "X-lc" && continue + ;; + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) + # Do not include libc due to us having libc/libc_r. + test "X$arg" = "X-lc" && continue + ;; + *-*-rhapsody* | *-*-darwin1.[012]) + # Rhapsody C and math libraries are in the System framework + deplibs="$deplibs -framework System" + continue + ;; + *-*-sco3.2v5* | *-*-sco5v6*) + # Causes problems with __ctype + test "X$arg" = "X-lc" && continue + ;; + *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) + # Compiler inserts libc in the correct place for threads to work + test "X$arg" = "X-lc" && continue + ;; + esac + elif test "X$arg" = "X-lc_r"; then + case $host in + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) + # Do not include libc_r directly, use -pthread flag. + continue + ;; + esac + fi + deplibs="$deplibs $arg" + continue + ;; + + # Tru64 UNIX uses -model [arg] to determine the layout of C++ + # classes, name mangling, and exception handling. + -model) + compile_command="$compile_command $arg" + compiler_flags="$compiler_flags $arg" + finalize_command="$finalize_command $arg" + prev=xcompiler + continue + ;; + + -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe|-threads) + compiler_flags="$compiler_flags $arg" + compile_command="$compile_command $arg" + finalize_command="$finalize_command $arg" + continue + ;; + + -multi_module) + single_module="${wl}-multi_module" + continue + ;; + + -module) + module=yes + continue + ;; + + # -64, -mips[0-9] enable 64-bit mode on the SGI compiler + # -r[0-9][0-9]* specifies the processor on the SGI compiler + # -xarch=*, -xtarget=* enable 64-bit mode on the Sun compiler + # +DA*, +DD* enable 64-bit mode on the HP compiler + # -q* pass through compiler args for the IBM compiler + # -m* pass through architecture-specific compiler args for GCC + # -m*, -t[45]*, -txscale* pass through architecture-specific + # compiler args for GCC + # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC + # -F/path gives path to uninstalled frameworks, gcc on darwin + # @file GCC response files + -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \ + -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*) + + # Unknown arguments in both finalize_command and compile_command need + # to be aesthetically quoted because they are evaled later. + arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + compile_command="$compile_command $arg" + finalize_command="$finalize_command $arg" + compiler_flags="$compiler_flags $arg" + continue + ;; + + -shrext) + prev=shrext + continue + ;; + + -no-fast-install) + fast_install=no + continue + ;; + + -no-install) + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-darwin*) + # The PATH hackery in wrapper scripts is required on Windows + # and Darwin in order for the loader to find any dlls it needs. + $echo "$modename: warning: \`-no-install' is ignored for $host" 1>&2 + $echo "$modename: warning: assuming \`-no-fast-install' instead" 1>&2 + fast_install=no + ;; + *) no_install=yes ;; + esac + continue + ;; + + -no-undefined) + allow_undefined=no + continue + ;; + + -objectlist) + prev=objectlist + continue + ;; + + -o) prev=output ;; + + -precious-files-regex) + prev=precious_regex + continue + ;; + + -release) + prev=release + continue + ;; + + -rpath) + prev=rpath + continue + ;; + + -R) + prev=xrpath + continue + ;; + + -R*) + dir=`$echo "X$arg" | $Xsed -e 's/^-R//'` + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + $echo "$modename: only absolute run-paths are allowed" 1>&2 + exit $EXIT_FAILURE + ;; + esac + case "$xrpath " in + *" $dir "*) ;; + *) xrpath="$xrpath $dir" ;; + esac + continue + ;; + + -static | -static-libtool-libs) + # The effects of -static are defined in a previous loop. + # We used to do the same as -all-static on platforms that + # didn't have a PIC flag, but the assumption that the effects + # would be equivalent was wrong. It would break on at least + # Digital Unix and AIX. + continue + ;; + + -thread-safe) + thread_safe=yes + continue + ;; + + -version-info) + prev=vinfo + continue + ;; + -version-number) + prev=vinfo + vinfo_number=yes + continue + ;; + + -Wc,*) + args=`$echo "X$arg" | $Xsed -e "$sed_quote_subst" -e 's/^-Wc,//'` + arg= + save_ifs="$IFS"; IFS=',' + for flag in $args; do + IFS="$save_ifs" + case $flag in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + flag="\"$flag\"" + ;; + esac + arg="$arg $wl$flag" + compiler_flags="$compiler_flags $flag" + done + IFS="$save_ifs" + arg=`$echo "X$arg" | $Xsed -e "s/^ //"` + ;; + + -Wl,*) + args=`$echo "X$arg" | $Xsed -e "$sed_quote_subst" -e 's/^-Wl,//'` + arg= + save_ifs="$IFS"; IFS=',' + for flag in $args; do + IFS="$save_ifs" + case $flag in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + flag="\"$flag\"" + ;; + esac + arg="$arg $wl$flag" + compiler_flags="$compiler_flags $wl$flag" + linker_flags="$linker_flags $flag" + done + IFS="$save_ifs" + arg=`$echo "X$arg" | $Xsed -e "s/^ //"` + ;; + + -Xcompiler) + prev=xcompiler + continue + ;; + + -Xlinker) + prev=xlinker + continue + ;; + + -XCClinker) + prev=xcclinker + continue + ;; + + # Some other compiler flag. + -* | +*) + # Unknown arguments in both finalize_command and compile_command need + # to be aesthetically quoted because they are evaled later. + arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + ;; + + *.$objext) + # A standard object. + objs="$objs $arg" + ;; + + *.lo) + # A libtool-controlled object. + + # Check to see that this really is a libtool object. + if (${SED} -e '2q' $arg | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + pic_object= + non_pic_object= + + # Read the .lo file + # If there is no directory component, then add one. + case $arg in + */* | *\\*) . $arg ;; + *) . ./$arg ;; + esac + + if test -z "$pic_object" || \ + test -z "$non_pic_object" || + test "$pic_object" = none && \ + test "$non_pic_object" = none; then + $echo "$modename: cannot find name of object for \`$arg'" 1>&2 + exit $EXIT_FAILURE + fi + + # Extract subdirectory from the argument. + xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'` + if test "X$xdir" = "X$arg"; then + xdir= + else + xdir="$xdir/" + fi + + if test "$pic_object" != none; then + # Prepend the subdirectory the object is found in. + pic_object="$xdir$pic_object" + + if test "$prev" = dlfiles; then + if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then + dlfiles="$dlfiles $pic_object" + prev= + continue + else + # If libtool objects are unsupported, then we need to preload. + prev=dlprefiles + fi + fi + + # CHECK ME: I think I busted this. -Ossama + if test "$prev" = dlprefiles; then + # Preload the old-style object. + dlprefiles="$dlprefiles $pic_object" + prev= + fi + + # A PIC object. + libobjs="$libobjs $pic_object" + arg="$pic_object" + fi + + # Non-PIC object. + if test "$non_pic_object" != none; then + # Prepend the subdirectory the object is found in. + non_pic_object="$xdir$non_pic_object" + + # A standard non-PIC object + non_pic_objects="$non_pic_objects $non_pic_object" + if test -z "$pic_object" || test "$pic_object" = none ; then + arg="$non_pic_object" + fi + else + # If the PIC object exists, use it instead. + # $xdir was prepended to $pic_object above. + non_pic_object="$pic_object" + non_pic_objects="$non_pic_objects $non_pic_object" + fi + else + # Only an error if not doing a dry-run. + if test -z "$run"; then + $echo "$modename: \`$arg' is not a valid libtool object" 1>&2 + exit $EXIT_FAILURE + else + # Dry-run case. + + # Extract subdirectory from the argument. + xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'` + if test "X$xdir" = "X$arg"; then + xdir= + else + xdir="$xdir/" + fi + + pic_object=`$echo "X${xdir}${objdir}/${arg}" | $Xsed -e "$lo2o"` + non_pic_object=`$echo "X${xdir}${arg}" | $Xsed -e "$lo2o"` + libobjs="$libobjs $pic_object" + non_pic_objects="$non_pic_objects $non_pic_object" + fi + fi + ;; + + *.$libext) + # An archive. + deplibs="$deplibs $arg" + old_deplibs="$old_deplibs $arg" + continue + ;; + + *.la) + # A libtool-controlled library. + + if test "$prev" = dlfiles; then + # This library was specified with -dlopen. + dlfiles="$dlfiles $arg" + prev= + elif test "$prev" = dlprefiles; then + # The library was specified with -dlpreopen. + dlprefiles="$dlprefiles $arg" + prev= + else + deplibs="$deplibs $arg" + fi + continue + ;; + + # Some other compiler argument. + *) + # Unknown arguments in both finalize_command and compile_command need + # to be aesthetically quoted because they are evaled later. + arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + ;; + esac # arg + + # Now actually substitute the argument into the commands. + if test -n "$arg"; then + compile_command="$compile_command $arg" + finalize_command="$finalize_command $arg" + fi + done # argument parsing loop + + if test -n "$prev"; then + $echo "$modename: the \`$prevarg' option requires an argument" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then + eval arg=\"$export_dynamic_flag_spec\" + compile_command="$compile_command $arg" + finalize_command="$finalize_command $arg" + fi + + oldlibs= + # calculate the name of the file, without its directory + outputname=`$echo "X$output" | $Xsed -e 's%^.*/%%'` + libobjs_save="$libobjs" + + if test -n "$shlibpath_var"; then + # get the directories listed in $shlibpath_var + eval shlib_search_path=\`\$echo \"X\${$shlibpath_var}\" \| \$Xsed -e \'s/:/ /g\'\` + else + shlib_search_path= + fi + eval sys_lib_search_path=\"$sys_lib_search_path_spec\" + eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\" + + output_objdir=`$echo "X$output" | $Xsed -e 's%/[^/]*$%%'` + if test "X$output_objdir" = "X$output"; then + output_objdir="$objdir" + else + output_objdir="$output_objdir/$objdir" + fi + # Create the object directory. + if test ! -d "$output_objdir"; then + $show "$mkdir $output_objdir" + $run $mkdir $output_objdir + exit_status=$? + if test "$exit_status" -ne 0 && test ! -d "$output_objdir"; then + exit $exit_status + fi + fi + + # Determine the type of output + case $output in + "") + $echo "$modename: you must specify an output file" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + ;; + *.$libext) linkmode=oldlib ;; + *.lo | *.$objext) linkmode=obj ;; + *.la) linkmode=lib ;; + *) linkmode=prog ;; # Anything else should be a program. + esac + + case $host in + *cygwin* | *mingw* | *pw32*) + # don't eliminate duplications in $postdeps and $predeps + duplicate_compiler_generated_deps=yes + ;; + *) + duplicate_compiler_generated_deps=$duplicate_deps + ;; + esac + specialdeplibs= + + libs= + # Find all interdependent deplibs by searching for libraries + # that are linked more than once (e.g. -la -lb -la) + for deplib in $deplibs; do + if test "X$duplicate_deps" = "Xyes" ; then + case "$libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + fi + libs="$libs $deplib" + done + + if test "$linkmode" = lib; then + libs="$predeps $libs $compiler_lib_search_path $postdeps" + + # Compute libraries that are listed more than once in $predeps + # $postdeps and mark them as special (i.e., whose duplicates are + # not to be eliminated). + pre_post_deps= + if test "X$duplicate_compiler_generated_deps" = "Xyes" ; then + for pre_post_dep in $predeps $postdeps; do + case "$pre_post_deps " in + *" $pre_post_dep "*) specialdeplibs="$specialdeplibs $pre_post_deps" ;; + esac + pre_post_deps="$pre_post_deps $pre_post_dep" + done + fi + pre_post_deps= + fi + + deplibs= + newdependency_libs= + newlib_search_path= + need_relink=no # whether we're linking any uninstalled libtool libraries + notinst_deplibs= # not-installed libtool libraries + case $linkmode in + lib) + passes="conv link" + for file in $dlfiles $dlprefiles; do + case $file in + *.la) ;; + *) + $echo "$modename: libraries can \`-dlopen' only libtool libraries: $file" 1>&2 + exit $EXIT_FAILURE + ;; + esac + done + ;; + prog) + compile_deplibs= + finalize_deplibs= + alldeplibs=no + newdlfiles= + newdlprefiles= + passes="conv scan dlopen dlpreopen link" + ;; + *) passes="conv" + ;; + esac + for pass in $passes; do + if test "$linkmode,$pass" = "lib,link" || + test "$linkmode,$pass" = "prog,scan"; then + libs="$deplibs" + deplibs= + fi + if test "$linkmode" = prog; then + case $pass in + dlopen) libs="$dlfiles" ;; + dlpreopen) libs="$dlprefiles" ;; + link) libs="$deplibs %DEPLIBS% $dependency_libs" ;; + esac + fi + if test "$pass" = dlopen; then + # Collect dlpreopened libraries + save_deplibs="$deplibs" + deplibs= + fi + for deplib in $libs; do + lib= + found=no + case $deplib in + -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe|-threads) + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + compiler_flags="$compiler_flags $deplib" + fi + continue + ;; + -l*) + if test "$linkmode" != lib && test "$linkmode" != prog; then + $echo "$modename: warning: \`-l' is ignored for archives/objects" 1>&2 + continue + fi + name=`$echo "X$deplib" | $Xsed -e 's/^-l//'` + if test "$linkmode" = lib; then + searchdirs="$newlib_search_path $lib_search_path $compiler_lib_search_dirs $sys_lib_search_path $shlib_search_path" + else + searchdirs="$newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path" + fi + for searchdir in $searchdirs; do + for search_ext in .la $std_shrext .so .a; do + # Search the libtool library + lib="$searchdir/lib${name}${search_ext}" + if test -f "$lib"; then + if test "$search_ext" = ".la"; then + found=yes + else + found=no + fi + break 2 + fi + done + done + if test "$found" != yes; then + # deplib doesn't seem to be a libtool library + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" + fi + continue + else # deplib is a libtool library + # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib, + # We need to do some special things here, and not later. + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + case " $predeps $postdeps " in + *" $deplib "*) + if (${SED} -e '2q' $lib | + grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + library_names= + old_library= + case $lib in + */* | *\\*) . $lib ;; + *) . ./$lib ;; + esac + for l in $old_library $library_names; do + ll="$l" + done + if test "X$ll" = "X$old_library" ; then # only static version available + found=no + ladir=`$echo "X$lib" | $Xsed -e 's%/[^/]*$%%'` + test "X$ladir" = "X$lib" && ladir="." + lib=$ladir/$old_library + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" + fi + continue + fi + fi + ;; + *) ;; + esac + fi + fi + ;; # -l + -L*) + case $linkmode in + lib) + deplibs="$deplib $deplibs" + test "$pass" = conv && continue + newdependency_libs="$deplib $newdependency_libs" + newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'` + ;; + prog) + if test "$pass" = conv; then + deplibs="$deplib $deplibs" + continue + fi + if test "$pass" = scan; then + deplibs="$deplib $deplibs" + else + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + fi + newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'` + ;; + *) + $echo "$modename: warning: \`-L' is ignored for archives/objects" 1>&2 + ;; + esac # linkmode + continue + ;; # -L + -R*) + if test "$pass" = link; then + dir=`$echo "X$deplib" | $Xsed -e 's/^-R//'` + # Make sure the xrpath contains only unique directories. + case "$xrpath " in + *" $dir "*) ;; + *) xrpath="$xrpath $dir" ;; + esac + fi + deplibs="$deplib $deplibs" + continue + ;; + *.la) lib="$deplib" ;; + *.$libext) + if test "$pass" = conv; then + deplibs="$deplib $deplibs" + continue + fi + case $linkmode in + lib) + valid_a_lib=no + case $deplibs_check_method in + match_pattern*) + set dummy $deplibs_check_method + match_pattern_regex=`expr "$deplibs_check_method" : "$2 \(.*\)"` + if eval $echo \"$deplib\" 2>/dev/null \ + | $SED 10q \ + | $EGREP "$match_pattern_regex" > /dev/null; then + valid_a_lib=yes + fi + ;; + pass_all) + valid_a_lib=yes + ;; + esac + if test "$valid_a_lib" != yes; then + $echo + $echo "*** Warning: Trying to link with static lib archive $deplib." + $echo "*** I have the capability to make that library automatically link in when" + $echo "*** you link to this library. But I can only do this if you have a" + $echo "*** shared version of the library, which you do not appear to have" + $echo "*** because the file extensions .$libext of this argument makes me believe" + $echo "*** that it is just a static archive that I should not used here." + else + $echo + $echo "*** Warning: Linking the shared library $output against the" + $echo "*** static library $deplib is not portable!" + deplibs="$deplib $deplibs" + fi + continue + ;; + prog) + if test "$pass" != link; then + deplibs="$deplib $deplibs" + else + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + fi + continue + ;; + esac # linkmode + ;; # *.$libext + *.lo | *.$objext) + if test "$pass" = conv; then + deplibs="$deplib $deplibs" + elif test "$linkmode" = prog; then + if test "$pass" = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then + # If there is no dlopen support or we're linking statically, + # we need to preload. + newdlprefiles="$newdlprefiles $deplib" + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + newdlfiles="$newdlfiles $deplib" + fi + fi + continue + ;; + %DEPLIBS%) + alldeplibs=yes + continue + ;; + esac # case $deplib + if test "$found" = yes || test -f "$lib"; then : + else + $echo "$modename: cannot find the library \`$lib' or unhandled argument \`$deplib'" 1>&2 + exit $EXIT_FAILURE + fi + + # Check to see that this really is a libtool archive. + if (${SED} -e '2q' $lib | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then : + else + $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 + exit $EXIT_FAILURE + fi + + ladir=`$echo "X$lib" | $Xsed -e 's%/[^/]*$%%'` + test "X$ladir" = "X$lib" && ladir="." + + dlname= + dlopen= + dlpreopen= + libdir= + library_names= + old_library= + # If the library was installed with an old release of libtool, + # it will not redefine variables installed, or shouldnotlink + installed=yes + shouldnotlink=no + avoidtemprpath= + + + # Read the .la file + case $lib in + */* | *\\*) . $lib ;; + *) . ./$lib ;; + esac + + if test "$linkmode,$pass" = "lib,link" || + test "$linkmode,$pass" = "prog,scan" || + { test "$linkmode" != prog && test "$linkmode" != lib; }; then + test -n "$dlopen" && dlfiles="$dlfiles $dlopen" + test -n "$dlpreopen" && dlprefiles="$dlprefiles $dlpreopen" + fi + + if test "$pass" = conv; then + # Only check for convenience libraries + deplibs="$lib $deplibs" + if test -z "$libdir"; then + if test -z "$old_library"; then + $echo "$modename: cannot find name of link library for \`$lib'" 1>&2 + exit $EXIT_FAILURE + fi + # It is a libtool convenience library, so add in its objects. + convenience="$convenience $ladir/$objdir/$old_library" + old_convenience="$old_convenience $ladir/$objdir/$old_library" + tmp_libs= + for deplib in $dependency_libs; do + deplibs="$deplib $deplibs" + if test "X$duplicate_deps" = "Xyes" ; then + case "$tmp_libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + fi + tmp_libs="$tmp_libs $deplib" + done + elif test "$linkmode" != prog && test "$linkmode" != lib; then + $echo "$modename: \`$lib' is not a convenience library" 1>&2 + exit $EXIT_FAILURE + fi + continue + fi # $pass = conv + + + # Get the name of the library we link against. + linklib= + for l in $old_library $library_names; do + linklib="$l" + done + if test -z "$linklib"; then + $echo "$modename: cannot find name of link library for \`$lib'" 1>&2 + exit $EXIT_FAILURE + fi + + # This library was specified with -dlopen. + if test "$pass" = dlopen; then + if test -z "$libdir"; then + $echo "$modename: cannot -dlopen a convenience library: \`$lib'" 1>&2 + exit $EXIT_FAILURE + fi + if test -z "$dlname" || + test "$dlopen_support" != yes || + test "$build_libtool_libs" = no; then + # If there is no dlname, no dlopen support or we're linking + # statically, we need to preload. We also need to preload any + # dependent libraries so libltdl's deplib preloader doesn't + # bomb out in the load deplibs phase. + dlprefiles="$dlprefiles $lib $dependency_libs" + else + newdlfiles="$newdlfiles $lib" + fi + continue + fi # $pass = dlopen + + # We need an absolute path. + case $ladir in + [\\/]* | [A-Za-z]:[\\/]*) abs_ladir="$ladir" ;; + *) + abs_ladir=`cd "$ladir" && pwd` + if test -z "$abs_ladir"; then + $echo "$modename: warning: cannot determine absolute directory name of \`$ladir'" 1>&2 + $echo "$modename: passing it literally to the linker, although it might fail" 1>&2 + abs_ladir="$ladir" + fi + ;; + esac + laname=`$echo "X$lib" | $Xsed -e 's%^.*/%%'` + + # Find the relevant object directory and library name. + if test "X$installed" = Xyes; then + if test ! -f "$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then + $echo "$modename: warning: library \`$lib' was moved." 1>&2 + dir="$ladir" + absdir="$abs_ladir" + libdir="$abs_ladir" + else + dir="$libdir" + absdir="$libdir" + fi + test "X$hardcode_automatic" = Xyes && avoidtemprpath=yes + else + if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then + dir="$ladir" + absdir="$abs_ladir" + # Remove this search path later + notinst_path="$notinst_path $abs_ladir" + else + dir="$ladir/$objdir" + absdir="$abs_ladir/$objdir" + # Remove this search path later + notinst_path="$notinst_path $abs_ladir" + fi + fi # $installed = yes + name=`$echo "X$laname" | $Xsed -e 's/\.la$//' -e 's/^lib//'` + + # This library was specified with -dlpreopen. + if test "$pass" = dlpreopen; then + if test -z "$libdir"; then + $echo "$modename: cannot -dlpreopen a convenience library: \`$lib'" 1>&2 + exit $EXIT_FAILURE + fi + # Prefer using a static library (so that no silly _DYNAMIC symbols + # are required to link). + if test -n "$old_library"; then + newdlprefiles="$newdlprefiles $dir/$old_library" + # Otherwise, use the dlname, so that lt_dlopen finds it. + elif test -n "$dlname"; then + newdlprefiles="$newdlprefiles $dir/$dlname" + else + newdlprefiles="$newdlprefiles $dir/$linklib" + fi + fi # $pass = dlpreopen + + if test -z "$libdir"; then + # Link the convenience library + if test "$linkmode" = lib; then + deplibs="$dir/$old_library $deplibs" + elif test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$dir/$old_library $compile_deplibs" + finalize_deplibs="$dir/$old_library $finalize_deplibs" + else + deplibs="$lib $deplibs" # used for prog,scan pass + fi + continue + fi + + + if test "$linkmode" = prog && test "$pass" != link; then + newlib_search_path="$newlib_search_path $ladir" + deplibs="$lib $deplibs" + + linkalldeplibs=no + if test "$link_all_deplibs" != no || test -z "$library_names" || + test "$build_libtool_libs" = no; then + linkalldeplibs=yes + fi + + tmp_libs= + for deplib in $dependency_libs; do + case $deplib in + -L*) newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'`;; ### testsuite: skip nested quoting test + esac + # Need to link against all dependency_libs? + if test "$linkalldeplibs" = yes; then + deplibs="$deplib $deplibs" + else + # Need to hardcode shared library paths + # or/and link against static libraries + newdependency_libs="$deplib $newdependency_libs" + fi + if test "X$duplicate_deps" = "Xyes" ; then + case "$tmp_libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + fi + tmp_libs="$tmp_libs $deplib" + done # for deplib + continue + fi # $linkmode = prog... + + if test "$linkmode,$pass" = "prog,link"; then + if test -n "$library_names" && + { { test "$prefer_static_libs" = no || + test "$prefer_static_libs,$installed" = "built,yes"; } || + test -z "$old_library"; }; then + # We need to hardcode the library path + if test -n "$shlibpath_var" && test -z "$avoidtemprpath" ; then + # Make sure the rpath contains only unique directories. + case "$temp_rpath " in + *" $dir "*) ;; + *" $absdir "*) ;; + *) temp_rpath="$temp_rpath $absdir" ;; + esac + fi + + # Hardcode the library path. + # Skip directories that are in the system default run-time + # search path. + case " $sys_lib_dlsearch_path " in + *" $absdir "*) ;; + *) + case "$compile_rpath " in + *" $absdir "*) ;; + *) compile_rpath="$compile_rpath $absdir" + esac + ;; + esac + case " $sys_lib_dlsearch_path " in + *" $libdir "*) ;; + *) + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" + esac + ;; + esac + fi # $linkmode,$pass = prog,link... + + if test "$alldeplibs" = yes && + { test "$deplibs_check_method" = pass_all || + { test "$build_libtool_libs" = yes && + test -n "$library_names"; }; }; then + # We only need to search for static libraries + continue + fi + fi + + link_static=no # Whether the deplib will be linked statically + use_static_libs=$prefer_static_libs + if test "$use_static_libs" = built && test "$installed" = yes ; then + use_static_libs=no + fi + if test -n "$library_names" && + { test "$use_static_libs" = no || test -z "$old_library"; }; then + if test "$installed" = no; then + notinst_deplibs="$notinst_deplibs $lib" + need_relink=yes + fi + # This is a shared library + + # Warn about portability, can't link against -module's on + # some systems (darwin) + if test "$shouldnotlink" = yes && test "$pass" = link ; then + $echo + if test "$linkmode" = prog; then + $echo "*** Warning: Linking the executable $output against the loadable module" + else + $echo "*** Warning: Linking the shared library $output against the loadable module" + fi + $echo "*** $linklib is not portable!" + fi + if test "$linkmode" = lib && + test "$hardcode_into_libs" = yes; then + # Hardcode the library path. + # Skip directories that are in the system default run-time + # search path. + case " $sys_lib_dlsearch_path " in + *" $absdir "*) ;; + *) + case "$compile_rpath " in + *" $absdir "*) ;; + *) compile_rpath="$compile_rpath $absdir" + esac + ;; + esac + case " $sys_lib_dlsearch_path " in + *" $libdir "*) ;; + *) + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" + esac + ;; + esac + fi + + if test -n "$old_archive_from_expsyms_cmds"; then + # figure out the soname + set dummy $library_names + realname="$2" + shift; shift + libname=`eval \\$echo \"$libname_spec\"` + # use dlname if we got it. it's perfectly good, no? + if test -n "$dlname"; then + soname="$dlname" + elif test -n "$soname_spec"; then + # bleh windows + case $host in + *cygwin* | mingw*) + major=`expr $current - $age` + versuffix="-$major" + ;; + esac + eval soname=\"$soname_spec\" + else + soname="$realname" + fi + + # Make a new name for the extract_expsyms_cmds to use + soroot="$soname" + soname=`$echo $soroot | ${SED} -e 's/^.*\///'` + newlib="libimp-`$echo $soname | ${SED} 's/^lib//;s/\.dll$//'`.a" + + # If the library has no export list, then create one now + if test -f "$output_objdir/$soname-def"; then : + else + $show "extracting exported symbol list from \`$soname'" + save_ifs="$IFS"; IFS='~' + cmds=$extract_expsyms_cmds + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + fi + + # Create $newlib + if test -f "$output_objdir/$newlib"; then :; else + $show "generating import library for \`$soname'" + save_ifs="$IFS"; IFS='~' + cmds=$old_archive_from_expsyms_cmds + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + fi + # make sure the library variables are pointing to the new library + dir=$output_objdir + linklib=$newlib + fi # test -n "$old_archive_from_expsyms_cmds" + + if test "$linkmode" = prog || test "$mode" != relink; then + add_shlibpath= + add_dir= + add= + lib_linked=yes + case $hardcode_action in + immediate | unsupported) + if test "$hardcode_direct" = no; then + add="$dir/$linklib" + case $host in + *-*-sco3.2v5.0.[024]*) add_dir="-L$dir" ;; + *-*-sysv4*uw2*) add_dir="-L$dir" ;; + *-*-sysv5OpenUNIX* | *-*-sysv5UnixWare7.[01].[10]* | \ + *-*-unixware7*) add_dir="-L$dir" ;; + *-*-darwin* ) + # if the lib is a module then we can not link against + # it, someone is ignoring the new warnings I added + if /usr/bin/file -L $add 2> /dev/null | + $EGREP ": [^:]* bundle" >/dev/null ; then + $echo "** Warning, lib $linklib is a module, not a shared library" + if test -z "$old_library" ; then + $echo + $echo "** And there doesn't seem to be a static archive available" + $echo "** The link will probably fail, sorry" + else + add="$dir/$old_library" + fi + fi + esac + elif test "$hardcode_minus_L" = no; then + case $host in + *-*-sunos*) add_shlibpath="$dir" ;; + esac + add_dir="-L$dir" + add="-l$name" + elif test "$hardcode_shlibpath_var" = no; then + add_shlibpath="$dir" + add="-l$name" + else + lib_linked=no + fi + ;; + relink) + if test "$hardcode_direct" = yes; then + add="$dir/$linklib" + elif test "$hardcode_minus_L" = yes; then + add_dir="-L$dir" + # Try looking first in the location we're being installed to. + if test -n "$inst_prefix_dir"; then + case $libdir in + [\\/]*) + add_dir="$add_dir -L$inst_prefix_dir$libdir" + ;; + esac + fi + add="-l$name" + elif test "$hardcode_shlibpath_var" = yes; then + add_shlibpath="$dir" + add="-l$name" + else + lib_linked=no + fi + ;; + *) lib_linked=no ;; + esac + + if test "$lib_linked" != yes; then + $echo "$modename: configuration error: unsupported hardcode properties" + exit $EXIT_FAILURE + fi + + if test -n "$add_shlibpath"; then + case :$compile_shlibpath: in + *":$add_shlibpath:"*) ;; + *) compile_shlibpath="$compile_shlibpath$add_shlibpath:" ;; + esac + fi + if test "$linkmode" = prog; then + test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs" + test -n "$add" && compile_deplibs="$add $compile_deplibs" + else + test -n "$add_dir" && deplibs="$add_dir $deplibs" + test -n "$add" && deplibs="$add $deplibs" + if test "$hardcode_direct" != yes && \ + test "$hardcode_minus_L" != yes && \ + test "$hardcode_shlibpath_var" = yes; then + case :$finalize_shlibpath: in + *":$libdir:"*) ;; + *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;; + esac + fi + fi + fi + + if test "$linkmode" = prog || test "$mode" = relink; then + add_shlibpath= + add_dir= + add= + # Finalize command for both is simple: just hardcode it. + if test "$hardcode_direct" = yes; then + add="$libdir/$linklib" + elif test "$hardcode_minus_L" = yes; then + add_dir="-L$libdir" + add="-l$name" + elif test "$hardcode_shlibpath_var" = yes; then + case :$finalize_shlibpath: in + *":$libdir:"*) ;; + *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;; + esac + add="-l$name" + elif test "$hardcode_automatic" = yes; then + if test -n "$inst_prefix_dir" && + test -f "$inst_prefix_dir$libdir/$linklib" ; then + add="$inst_prefix_dir$libdir/$linklib" + else + add="$libdir/$linklib" + fi + else + # We cannot seem to hardcode it, guess we'll fake it. + add_dir="-L$libdir" + # Try looking first in the location we're being installed to. + if test -n "$inst_prefix_dir"; then + case $libdir in + [\\/]*) + add_dir="$add_dir -L$inst_prefix_dir$libdir" + ;; + esac + fi + add="-l$name" + fi + + if test "$linkmode" = prog; then + test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs" + test -n "$add" && finalize_deplibs="$add $finalize_deplibs" + else + test -n "$add_dir" && deplibs="$add_dir $deplibs" + test -n "$add" && deplibs="$add $deplibs" + fi + fi + elif test "$linkmode" = prog; then + # Here we assume that one of hardcode_direct or hardcode_minus_L + # is not unsupported. This is valid on all known static and + # shared platforms. + if test "$hardcode_direct" != unsupported; then + test -n "$old_library" && linklib="$old_library" + compile_deplibs="$dir/$linklib $compile_deplibs" + finalize_deplibs="$dir/$linklib $finalize_deplibs" + else + compile_deplibs="-l$name -L$dir $compile_deplibs" + finalize_deplibs="-l$name -L$dir $finalize_deplibs" + fi + elif test "$build_libtool_libs" = yes; then + # Not a shared library + if test "$deplibs_check_method" != pass_all; then + # We're trying link a shared library against a static one + # but the system doesn't support it. + + # Just print a warning and add the library to dependency_libs so + # that the program can be linked against the static library. + $echo + $echo "*** Warning: This system can not link to static lib archive $lib." + $echo "*** I have the capability to make that library automatically link in when" + $echo "*** you link to this library. But I can only do this if you have a" + $echo "*** shared version of the library, which you do not appear to have." + if test "$module" = yes; then + $echo "*** But as you try to build a module library, libtool will still create " + $echo "*** a static module, that should work as long as the dlopening application" + $echo "*** is linked with the -dlopen flag to resolve symbols at runtime." + if test -z "$global_symbol_pipe"; then + $echo + $echo "*** However, this would only work if libtool was able to extract symbol" + $echo "*** lists from a program, using \`nm' or equivalent, but libtool could" + $echo "*** not find such a program. So, this module is probably useless." + $echo "*** \`nm' from GNU binutils and a full rebuild may help." + fi + if test "$build_old_libs" = no; then + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + fi + else + deplibs="$dir/$old_library $deplibs" + link_static=yes + fi + fi # link shared/static library? + + if test "$linkmode" = lib; then + if test -n "$dependency_libs" && + { test "$hardcode_into_libs" != yes || + test "$build_old_libs" = yes || + test "$link_static" = yes; }; then + # Extract -R from dependency_libs + temp_deplibs= + for libdir in $dependency_libs; do + case $libdir in + -R*) temp_xrpath=`$echo "X$libdir" | $Xsed -e 's/^-R//'` + case " $xrpath " in + *" $temp_xrpath "*) ;; + *) xrpath="$xrpath $temp_xrpath";; + esac;; + *) temp_deplibs="$temp_deplibs $libdir";; + esac + done + dependency_libs="$temp_deplibs" + fi + + newlib_search_path="$newlib_search_path $absdir" + # Link against this library + test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs" + # ... and its dependency_libs + tmp_libs= + for deplib in $dependency_libs; do + newdependency_libs="$deplib $newdependency_libs" + if test "X$duplicate_deps" = "Xyes" ; then + case "$tmp_libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + fi + tmp_libs="$tmp_libs $deplib" + done + + if test "$link_all_deplibs" != no; then + # Add the search paths of all dependency libraries + for deplib in $dependency_libs; do + case $deplib in + -L*) path="$deplib" ;; + *.la) + dir=`$echo "X$deplib" | $Xsed -e 's%/[^/]*$%%'` + test "X$dir" = "X$deplib" && dir="." + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) absdir="$dir" ;; + *) + absdir=`cd "$dir" && pwd` + if test -z "$absdir"; then + $echo "$modename: warning: cannot determine absolute directory name of \`$dir'" 1>&2 + absdir="$dir" + fi + ;; + esac + if grep "^installed=no" $deplib > /dev/null; then + path="$absdir/$objdir" + else + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` + if test -z "$libdir"; then + $echo "$modename: \`$deplib' is not a valid libtool archive" 1>&2 + exit $EXIT_FAILURE + fi + if test "$absdir" != "$libdir"; then + $echo "$modename: warning: \`$deplib' seems to be moved" 1>&2 + fi + path="$absdir" + fi + depdepl= + case $host in + *-*-darwin*) + # we do not want to link against static libs, + # but need to link against shared + eval deplibrary_names=`${SED} -n -e 's/^library_names=\(.*\)$/\1/p' $deplib` + eval deplibdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` + if test -n "$deplibrary_names" ; then + for tmp in $deplibrary_names ; do + depdepl=$tmp + done + if test -f "$deplibdir/$depdepl" ; then + depdepl="$deplibdir/$depdepl" + elif test -f "$path/$depdepl" ; then + depdepl="$path/$depdepl" + else + # Can't find it, oh well... + depdepl= + fi + # do not add paths which are already there + case " $newlib_search_path " in + *" $path "*) ;; + *) newlib_search_path="$newlib_search_path $path";; + esac + fi + path="" + ;; + *) + path="-L$path" + ;; + esac + ;; + -l*) + case $host in + *-*-darwin*) + # Again, we only want to link against shared libraries + eval tmp_libs=`$echo "X$deplib" | $Xsed -e "s,^\-l,,"` + for tmp in $newlib_search_path ; do + if test -f "$tmp/lib$tmp_libs.dylib" ; then + eval depdepl="$tmp/lib$tmp_libs.dylib" + break + fi + done + path="" + ;; + *) continue ;; + esac + ;; + *) continue ;; + esac + case " $deplibs " in + *" $path "*) ;; + *) deplibs="$path $deplibs" ;; + esac + case " $deplibs " in + *" $depdepl "*) ;; + *) deplibs="$depdepl $deplibs" ;; + esac + done + fi # link_all_deplibs != no + fi # linkmode = lib + done # for deplib in $libs + dependency_libs="$newdependency_libs" + if test "$pass" = dlpreopen; then + # Link the dlpreopened libraries before other libraries + for deplib in $save_deplibs; do + deplibs="$deplib $deplibs" + done + fi + if test "$pass" != dlopen; then + if test "$pass" != conv; then + # Make sure lib_search_path contains only unique directories. + lib_search_path= + for dir in $newlib_search_path; do + case "$lib_search_path " in + *" $dir "*) ;; + *) lib_search_path="$lib_search_path $dir" ;; + esac + done + newlib_search_path= + fi + + if test "$linkmode,$pass" != "prog,link"; then + vars="deplibs" + else + vars="compile_deplibs finalize_deplibs" + fi + for var in $vars dependency_libs; do + # Add libraries to $var in reverse order + eval tmp_libs=\"\$$var\" + new_libs= + for deplib in $tmp_libs; do + # FIXME: Pedantically, this is the right thing to do, so + # that some nasty dependency loop isn't accidentally + # broken: + #new_libs="$deplib $new_libs" + # Pragmatically, this seems to cause very few problems in + # practice: + case $deplib in + -L*) new_libs="$deplib $new_libs" ;; + -R*) ;; + *) + # And here is the reason: when a library appears more + # than once as an explicit dependence of a library, or + # is implicitly linked in more than once by the + # compiler, it is considered special, and multiple + # occurrences thereof are not removed. Compare this + # with having the same library being listed as a + # dependency of multiple other libraries: in this case, + # we know (pedantically, we assume) the library does not + # need to be listed more than once, so we keep only the + # last copy. This is not always right, but it is rare + # enough that we require users that really mean to play + # such unportable linking tricks to link the library + # using -Wl,-lname, so that libtool does not consider it + # for duplicate removal. + case " $specialdeplibs " in + *" $deplib "*) new_libs="$deplib $new_libs" ;; + *) + case " $new_libs " in + *" $deplib "*) ;; + *) new_libs="$deplib $new_libs" ;; + esac + ;; + esac + ;; + esac + done + tmp_libs= + for deplib in $new_libs; do + case $deplib in + -L*) + case " $tmp_libs " in + *" $deplib "*) ;; + *) tmp_libs="$tmp_libs $deplib" ;; + esac + ;; + *) tmp_libs="$tmp_libs $deplib" ;; + esac + done + eval $var=\"$tmp_libs\" + done # for var + fi + # Last step: remove runtime libs from dependency_libs + # (they stay in deplibs) + tmp_libs= + for i in $dependency_libs ; do + case " $predeps $postdeps $compiler_lib_search_path " in + *" $i "*) + i="" + ;; + esac + if test -n "$i" ; then + tmp_libs="$tmp_libs $i" + fi + done + dependency_libs=$tmp_libs + done # for pass + if test "$linkmode" = prog; then + dlfiles="$newdlfiles" + dlprefiles="$newdlprefiles" + fi + + case $linkmode in + oldlib) + case " $deplibs" in + *\ -l* | *\ -L*) + $echo "$modename: warning: \`-l' and \`-L' are ignored for archives" 1>&2 ;; + esac + + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + $echo "$modename: warning: \`-dlopen' is ignored for archives" 1>&2 + fi + + if test -n "$rpath"; then + $echo "$modename: warning: \`-rpath' is ignored for archives" 1>&2 + fi + + if test -n "$xrpath"; then + $echo "$modename: warning: \`-R' is ignored for archives" 1>&2 + fi + + if test -n "$vinfo"; then + $echo "$modename: warning: \`-version-info/-version-number' is ignored for archives" 1>&2 + fi + + if test -n "$release"; then + $echo "$modename: warning: \`-release' is ignored for archives" 1>&2 + fi + + if test -n "$export_symbols" || test -n "$export_symbols_regex"; then + $echo "$modename: warning: \`-export-symbols' is ignored for archives" 1>&2 + fi + + # Now set the variables for building old libraries. + build_libtool_libs=no + oldlibs="$output" + objs="$objs$old_deplibs" + ;; + + lib) + # Make sure we only generate libraries of the form `libNAME.la'. + case $outputname in + lib*) + name=`$echo "X$outputname" | $Xsed -e 's/\.la$//' -e 's/^lib//'` + eval shared_ext=\"$shrext_cmds\" + eval libname=\"$libname_spec\" + ;; + *) + if test "$module" = no; then + $echo "$modename: libtool library \`$output' must begin with \`lib'" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + if test "$need_lib_prefix" != no; then + # Add the "lib" prefix for modules if required + name=`$echo "X$outputname" | $Xsed -e 's/\.la$//'` + eval shared_ext=\"$shrext_cmds\" + eval libname=\"$libname_spec\" + else + libname=`$echo "X$outputname" | $Xsed -e 's/\.la$//'` + fi + ;; + esac + + if test -n "$objs"; then + if test "$deplibs_check_method" != pass_all; then + $echo "$modename: cannot build libtool library \`$output' from non-libtool objects on this host:$objs" 2>&1 + exit $EXIT_FAILURE + else + $echo + $echo "*** Warning: Linking the shared library $output against the non-libtool" + $echo "*** objects $objs is not portable!" + libobjs="$libobjs $objs" + fi + fi + + if test "$dlself" != no; then + $echo "$modename: warning: \`-dlopen self' is ignored for libtool libraries" 1>&2 + fi + + set dummy $rpath + if test "$#" -gt 2; then + $echo "$modename: warning: ignoring multiple \`-rpath's for a libtool library" 1>&2 + fi + install_libdir="$2" + + oldlibs= + if test -z "$rpath"; then + if test "$build_libtool_libs" = yes; then + # Building a libtool convenience library. + # Some compilers have problems with a `.al' extension so + # convenience libraries should have the same extension an + # archive normally would. + oldlibs="$output_objdir/$libname.$libext $oldlibs" + build_libtool_libs=convenience + build_old_libs=yes + fi + + if test -n "$vinfo"; then + $echo "$modename: warning: \`-version-info/-version-number' is ignored for convenience libraries" 1>&2 + fi + + if test -n "$release"; then + $echo "$modename: warning: \`-release' is ignored for convenience libraries" 1>&2 + fi + else + + # Parse the version information argument. + save_ifs="$IFS"; IFS=':' + set dummy $vinfo 0 0 0 + IFS="$save_ifs" + + if test -n "$8"; then + $echo "$modename: too many parameters to \`-version-info'" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + # convert absolute version numbers to libtool ages + # this retains compatibility with .la files and attempts + # to make the code below a bit more comprehensible + + case $vinfo_number in + yes) + number_major="$2" + number_minor="$3" + number_revision="$4" + # + # There are really only two kinds -- those that + # use the current revision as the major version + # and those that subtract age and use age as + # a minor version. But, then there is irix + # which has an extra 1 added just for fun + # + case $version_type in + darwin|linux|osf|windows|none) + current=`expr $number_major + $number_minor` + age="$number_minor" + revision="$number_revision" + ;; + freebsd-aout|freebsd-elf|sunos) + current="$number_major" + revision="$number_minor" + age="0" + ;; + irix|nonstopux) + current=`expr $number_major + $number_minor` + age="$number_minor" + revision="$number_minor" + lt_irix_increment=no + ;; + esac + ;; + no) + current="$2" + revision="$3" + age="$4" + ;; + esac + + # Check that each of the things are valid numbers. + case $current in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + $echo "$modename: CURRENT \`$current' must be a nonnegative integer" 1>&2 + $echo "$modename: \`$vinfo' is not valid version information" 1>&2 + exit $EXIT_FAILURE + ;; + esac + + case $revision in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + $echo "$modename: REVISION \`$revision' must be a nonnegative integer" 1>&2 + $echo "$modename: \`$vinfo' is not valid version information" 1>&2 + exit $EXIT_FAILURE + ;; + esac + + case $age in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + $echo "$modename: AGE \`$age' must be a nonnegative integer" 1>&2 + $echo "$modename: \`$vinfo' is not valid version information" 1>&2 + exit $EXIT_FAILURE + ;; + esac + + if test "$age" -gt "$current"; then + $echo "$modename: AGE \`$age' is greater than the current interface number \`$current'" 1>&2 + $echo "$modename: \`$vinfo' is not valid version information" 1>&2 + exit $EXIT_FAILURE + fi + + # Calculate the version variables. + major= + versuffix= + verstring= + case $version_type in + none) ;; + + darwin) + # Like Linux, but with the current version available in + # verstring for coding it into the library header + major=.`expr $current - $age` + versuffix="$major.$age.$revision" + # Darwin ld doesn't like 0 for these options... + minor_current=`expr $current + 1` + xlcverstring="${wl}-compatibility_version ${wl}$minor_current ${wl}-current_version ${wl}$minor_current.$revision" + verstring="-compatibility_version $minor_current -current_version $minor_current.$revision" + ;; + + freebsd-aout) + major=".$current" + versuffix=".$current.$revision"; + ;; + + freebsd-elf) + major=".$current" + versuffix=".$current"; + ;; + + irix | nonstopux) + if test "X$lt_irix_increment" = "Xno"; then + major=`expr $current - $age` + else + major=`expr $current - $age + 1` + fi + case $version_type in + nonstopux) verstring_prefix=nonstopux ;; + *) verstring_prefix=sgi ;; + esac + verstring="$verstring_prefix$major.$revision" + + # Add in all the interfaces that we are compatible with. + loop=$revision + while test "$loop" -ne 0; do + iface=`expr $revision - $loop` + loop=`expr $loop - 1` + verstring="$verstring_prefix$major.$iface:$verstring" + done + + # Before this point, $major must not contain `.'. + major=.$major + versuffix="$major.$revision" + ;; + + linux) + major=.`expr $current - $age` + versuffix="$major.$age.$revision" + ;; + + osf) + major=.`expr $current - $age` + versuffix=".$current.$age.$revision" + verstring="$current.$age.$revision" + + # Add in all the interfaces that we are compatible with. + loop=$age + while test "$loop" -ne 0; do + iface=`expr $current - $loop` + loop=`expr $loop - 1` + verstring="$verstring:${iface}.0" + done + + # Make executables depend on our current version. + verstring="$verstring:${current}.0" + ;; + + sunos) + major=".$current" + versuffix=".$current.$revision" + ;; + + windows) + # Use '-' rather than '.', since we only want one + # extension on DOS 8.3 filesystems. + major=`expr $current - $age` + versuffix="-$major" + ;; + + *) + $echo "$modename: unknown library version type \`$version_type'" 1>&2 + $echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2 + exit $EXIT_FAILURE + ;; + esac + + # Clear the version info if we defaulted, and they specified a release. + if test -z "$vinfo" && test -n "$release"; then + major= + case $version_type in + darwin) + # we can't check for "0.0" in archive_cmds due to quoting + # problems, so we reset it completely + verstring= + ;; + *) + verstring="0.0" + ;; + esac + if test "$need_version" = no; then + versuffix= + else + versuffix=".0.0" + fi + fi + + # Remove version info from name if versioning should be avoided + if test "$avoid_version" = yes && test "$need_version" = no; then + major= + versuffix= + verstring="" + fi + + # Check to see if the archive will have undefined symbols. + if test "$allow_undefined" = yes; then + if test "$allow_undefined_flag" = unsupported; then + $echo "$modename: warning: undefined symbols not allowed in $host shared libraries" 1>&2 + build_libtool_libs=no + build_old_libs=yes + fi + else + # Don't allow undefined symbols. + allow_undefined_flag="$no_undefined_flag" + fi + fi + + if test "$mode" != relink; then + # Remove our outputs, but don't remove object files since they + # may have been created when compiling PIC objects. + removelist= + tempremovelist=`$echo "$output_objdir/*"` + for p in $tempremovelist; do + case $p in + *.$objext) + ;; + $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/${libname}${release}.*) + if test "X$precious_files_regex" != "X"; then + if echo $p | $EGREP -e "$precious_files_regex" >/dev/null 2>&1 + then + continue + fi + fi + removelist="$removelist $p" + ;; + *) ;; + esac + done + if test -n "$removelist"; then + $show "${rm}r $removelist" + $run ${rm}r $removelist + fi + fi + + # Now set the variables for building old libraries. + if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then + oldlibs="$oldlibs $output_objdir/$libname.$libext" + + # Transform .lo files to .o files. + oldobjs="$objs "`$echo "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}'$/d' -e "$lo2o" | $NL2SP` + fi + + # Eliminate all temporary directories. + #for path in $notinst_path; do + # lib_search_path=`$echo "$lib_search_path " | ${SED} -e "s% $path % %g"` + # deplibs=`$echo "$deplibs " | ${SED} -e "s% -L$path % %g"` + # dependency_libs=`$echo "$dependency_libs " | ${SED} -e "s% -L$path % %g"` + #done + + if test -n "$xrpath"; then + # If the user specified any rpath flags, then add them. + temp_xrpath= + for libdir in $xrpath; do + temp_xrpath="$temp_xrpath -R$libdir" + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" ;; + esac + done + if test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes; then + dependency_libs="$temp_xrpath $dependency_libs" + fi + fi + + # Make sure dlfiles contains only unique files that won't be dlpreopened + old_dlfiles="$dlfiles" + dlfiles= + for lib in $old_dlfiles; do + case " $dlprefiles $dlfiles " in + *" $lib "*) ;; + *) dlfiles="$dlfiles $lib" ;; + esac + done + + # Make sure dlprefiles contains only unique files + old_dlprefiles="$dlprefiles" + dlprefiles= + for lib in $old_dlprefiles; do + case "$dlprefiles " in + *" $lib "*) ;; + *) dlprefiles="$dlprefiles $lib" ;; + esac + done + + if test "$build_libtool_libs" = yes; then + if test -n "$rpath"; then + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos*) + # these systems don't actually have a c library (as such)! + ;; + *-*-rhapsody* | *-*-darwin1.[012]) + # Rhapsody C library is in the System framework + deplibs="$deplibs -framework System" + ;; + *-*-netbsd*) + # Don't link with libc until the a.out ld.so is fixed. + ;; + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) + # Do not include libc due to us having libc/libc_r. + ;; + *-*-sco3.2v5* | *-*-sco5v6*) + # Causes problems with __ctype + ;; + *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) + # Compiler inserts libc in the correct place for threads to work + ;; + *) + # Add libc to deplibs on all other systems if necessary. + if test "$build_libtool_need_lc" = "yes"; then + deplibs="$deplibs -lc" + fi + ;; + esac + fi + + # Transform deplibs into only deplibs that can be linked in shared. + name_save=$name + libname_save=$libname + release_save=$release + versuffix_save=$versuffix + major_save=$major + # I'm not sure if I'm treating the release correctly. I think + # release should show up in the -l (ie -lgmp5) so we don't want to + # add it in twice. Is that correct? + release="" + versuffix="" + major="" + newdeplibs= + droppeddeps=no + case $deplibs_check_method in + pass_all) + # Don't check for shared/static. Everything works. + # This might be a little naive. We might want to check + # whether the library exists or not. But this is on + # osf3 & osf4 and I'm not really sure... Just + # implementing what was already the behavior. + newdeplibs=$deplibs + ;; + test_compile) + # This code stresses the "libraries are programs" paradigm to its + # limits. Maybe even breaks it. We compile a program, linking it + # against the deplibs as a proxy for the library. Then we can check + # whether they linked in statically or dynamically with ldd. + $rm conftest.c + cat > conftest.c </dev/null` + for potent_lib in $potential_libs; do + # Follow soft links. + if ls -lLd "$potent_lib" 2>/dev/null \ + | grep " -> " >/dev/null; then + continue + fi + # The statement above tries to avoid entering an + # endless loop below, in case of cyclic links. + # We might still enter an endless loop, since a link + # loop can be closed while we follow links, + # but so what? + potlib="$potent_lib" + while test -h "$potlib" 2>/dev/null; do + potliblink=`ls -ld $potlib | ${SED} 's/.* -> //'` + case $potliblink in + [\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";; + *) potlib=`$echo "X$potlib" | $Xsed -e 's,[^/]*$,,'`"$potliblink";; + esac + done + if eval $file_magic_cmd \"\$potlib\" 2>/dev/null \ + | ${SED} 10q \ + | $EGREP "$file_magic_regex" > /dev/null; then + newdeplibs="$newdeplibs $a_deplib" + a_deplib="" + break 2 + fi + done + done + fi + if test -n "$a_deplib" ; then + droppeddeps=yes + $echo + $echo "*** Warning: linker path does not have real file for library $a_deplib." + $echo "*** I have the capability to make that library automatically link in when" + $echo "*** you link to this library. But I can only do this if you have a" + $echo "*** shared version of the library, which you do not appear to have" + $echo "*** because I did check the linker path looking for a file starting" + if test -z "$potlib" ; then + $echo "*** with $libname but no candidates were found. (...for file magic test)" + else + $echo "*** with $libname and none of the candidates passed a file format test" + $echo "*** using a file magic. Last file checked: $potlib" + fi + fi + else + # Add a -L argument. + newdeplibs="$newdeplibs $a_deplib" + fi + done # Gone through all deplibs. + ;; + match_pattern*) + set dummy $deplibs_check_method + match_pattern_regex=`expr "$deplibs_check_method" : "$2 \(.*\)"` + for a_deplib in $deplibs; do + name=`expr $a_deplib : '-l\(.*\)'` + # If $name is empty we are operating on a -L argument. + if test -n "$name" && test "$name" != "0"; then + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + case " $predeps $postdeps " in + *" $a_deplib "*) + newdeplibs="$newdeplibs $a_deplib" + a_deplib="" + ;; + esac + fi + if test -n "$a_deplib" ; then + libname=`eval \\$echo \"$libname_spec\"` + for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do + potential_libs=`ls $i/$libname[.-]* 2>/dev/null` + for potent_lib in $potential_libs; do + potlib="$potent_lib" # see symlink-check above in file_magic test + if eval $echo \"$potent_lib\" 2>/dev/null \ + | ${SED} 10q \ + | $EGREP "$match_pattern_regex" > /dev/null; then + newdeplibs="$newdeplibs $a_deplib" + a_deplib="" + break 2 + fi + done + done + fi + if test -n "$a_deplib" ; then + droppeddeps=yes + $echo + $echo "*** Warning: linker path does not have real file for library $a_deplib." + $echo "*** I have the capability to make that library automatically link in when" + $echo "*** you link to this library. But I can only do this if you have a" + $echo "*** shared version of the library, which you do not appear to have" + $echo "*** because I did check the linker path looking for a file starting" + if test -z "$potlib" ; then + $echo "*** with $libname but no candidates were found. (...for regex pattern test)" + else + $echo "*** with $libname and none of the candidates passed a file format test" + $echo "*** using a regex pattern. Last file checked: $potlib" + fi + fi + else + # Add a -L argument. + newdeplibs="$newdeplibs $a_deplib" + fi + done # Gone through all deplibs. + ;; + none | unknown | *) + newdeplibs="" + tmp_deplibs=`$echo "X $deplibs" | $Xsed -e 's/ -lc$//' \ + -e 's/ -[LR][^ ]*//g'` + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + for i in $predeps $postdeps ; do + # can't use Xsed below, because $i might contain '/' + tmp_deplibs=`$echo "X $tmp_deplibs" | ${SED} -e "1s,^X,," -e "s,$i,,"` + done + fi + if $echo "X $tmp_deplibs" | $Xsed -e 's/[ ]//g' \ + | grep . >/dev/null; then + $echo + if test "X$deplibs_check_method" = "Xnone"; then + $echo "*** Warning: inter-library dependencies are not supported in this platform." + else + $echo "*** Warning: inter-library dependencies are not known to be supported." + fi + $echo "*** All declared inter-library dependencies are being dropped." + droppeddeps=yes + fi + ;; + esac + versuffix=$versuffix_save + major=$major_save + release=$release_save + libname=$libname_save + name=$name_save + + case $host in + *-*-rhapsody* | *-*-darwin1.[012]) + # On Rhapsody replace the C library is the System framework + newdeplibs=`$echo "X $newdeplibs" | $Xsed -e 's/ -lc / -framework System /'` + ;; + esac + + if test "$droppeddeps" = yes; then + if test "$module" = yes; then + $echo + $echo "*** Warning: libtool could not satisfy all declared inter-library" + $echo "*** dependencies of module $libname. Therefore, libtool will create" + $echo "*** a static module, that should work as long as the dlopening" + $echo "*** application is linked with the -dlopen flag." + if test -z "$global_symbol_pipe"; then + $echo + $echo "*** However, this would only work if libtool was able to extract symbol" + $echo "*** lists from a program, using \`nm' or equivalent, but libtool could" + $echo "*** not find such a program. So, this module is probably useless." + $echo "*** \`nm' from GNU binutils and a full rebuild may help." + fi + if test "$build_old_libs" = no; then + oldlibs="$output_objdir/$libname.$libext" + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + else + $echo "*** The inter-library dependencies that have been dropped here will be" + $echo "*** automatically added whenever a program is linked with this library" + $echo "*** or is declared to -dlopen it." + + if test "$allow_undefined" = no; then + $echo + $echo "*** Since this library must not contain undefined symbols," + $echo "*** because either the platform does not support them or" + $echo "*** it was explicitly requested with -no-undefined," + $echo "*** libtool will only create a static version of it." + if test "$build_old_libs" = no; then + oldlibs="$output_objdir/$libname.$libext" + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + fi + fi + fi + # Done checking deplibs! + deplibs=$newdeplibs + fi + + + # move library search paths that coincide with paths to not yet + # installed libraries to the beginning of the library search list + new_libs= + for path in $notinst_path; do + case " $new_libs " in + *" -L$path/$objdir "*) ;; + *) + case " $deplibs " in + *" -L$path/$objdir "*) + new_libs="$new_libs -L$path/$objdir" ;; + esac + ;; + esac + done + for deplib in $deplibs; do + case $deplib in + -L*) + case " $new_libs " in + *" $deplib "*) ;; + *) new_libs="$new_libs $deplib" ;; + esac + ;; + *) new_libs="$new_libs $deplib" ;; + esac + done + deplibs="$new_libs" + + + # All the library-specific variables (install_libdir is set above). + library_names= + old_library= + dlname= + + # Test again, we may have decided not to build it any more + if test "$build_libtool_libs" = yes; then + if test "$hardcode_into_libs" = yes; then + # Hardcode the library paths + hardcode_libdirs= + dep_rpath= + rpath="$finalize_rpath" + test "$mode" != relink && rpath="$compile_rpath$rpath" + for libdir in $rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + dep_rpath="$dep_rpath $flag" + fi + elif test -n "$runpath_var"; then + case "$perm_rpath " in + *" $libdir "*) ;; + *) perm_rpath="$perm_rpath $libdir" ;; + esac + fi + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + if test -n "$hardcode_libdir_flag_spec_ld"; then + case $archive_cmds in + *\$LD*) eval dep_rpath=\"$hardcode_libdir_flag_spec_ld\" ;; + *) eval dep_rpath=\"$hardcode_libdir_flag_spec\" ;; + esac + else + eval dep_rpath=\"$hardcode_libdir_flag_spec\" + fi + fi + if test -n "$runpath_var" && test -n "$perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $perm_rpath; do + rpath="$rpath$dir:" + done + eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var" + fi + test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs" + fi + + shlibpath="$finalize_shlibpath" + test "$mode" != relink && shlibpath="$compile_shlibpath$shlibpath" + if test -n "$shlibpath"; then + eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var" + fi + + # Get the real and link names of the library. + eval shared_ext=\"$shrext_cmds\" + eval library_names=\"$library_names_spec\" + set dummy $library_names + realname="$2" + shift; shift + + if test -n "$soname_spec"; then + eval soname=\"$soname_spec\" + else + soname="$realname" + fi + if test -z "$dlname"; then + dlname=$soname + fi + + lib="$output_objdir/$realname" + linknames= + for link + do + linknames="$linknames $link" + done + + # Use standard objects if they are pic + test -z "$pic_flag" && libobjs=`$echo "X$libobjs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + + # Prepare the list of exported symbols + if test -z "$export_symbols"; then + if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then + $show "generating symbol list for \`$libname.la'" + export_symbols="$output_objdir/$libname.exp" + $run $rm $export_symbols + cmds=$export_symbols_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + if len=`expr "X$cmd" : ".*"` && + test "$len" -le "$max_cmd_len" || test "$max_cmd_len" -le -1; then + $show "$cmd" + $run eval "$cmd" || exit $? + skipped_export=false + else + # The command line is too long to execute in one step. + $show "using reloadable object file for export list..." + skipped_export=: + # Break out early, otherwise skipped_export may be + # set to false by a later but shorter cmd. + break + fi + done + IFS="$save_ifs" + if test -n "$export_symbols_regex"; then + $show "$EGREP -e \"$export_symbols_regex\" \"$export_symbols\" > \"${export_symbols}T\"" + $run eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' + $show "$mv \"${export_symbols}T\" \"$export_symbols\"" + $run eval '$mv "${export_symbols}T" "$export_symbols"' + fi + fi + fi + + if test -n "$export_symbols" && test -n "$include_expsyms"; then + $run eval '$echo "X$include_expsyms" | $SP2NL >> "$export_symbols"' + fi + + tmp_deplibs= + for test_deplib in $deplibs; do + case " $convenience " in + *" $test_deplib "*) ;; + *) + tmp_deplibs="$tmp_deplibs $test_deplib" + ;; + esac + done + deplibs="$tmp_deplibs" + + if test -n "$convenience"; then + if test -n "$whole_archive_flag_spec"; then + save_libobjs=$libobjs + eval libobjs=\"\$libobjs $whole_archive_flag_spec\" + else + gentop="$output_objdir/${outputname}x" + generated="$generated $gentop" + + func_extract_archives $gentop $convenience + libobjs="$libobjs $func_extract_archives_result" + fi + fi + + if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then + eval flag=\"$thread_safe_flag_spec\" + linker_flags="$linker_flags $flag" + fi + + # Make a backup of the uninstalled library when relinking + if test "$mode" = relink; then + $run eval '(cd $output_objdir && $rm ${realname}U && $mv $realname ${realname}U)' || exit $? + fi + + # Do each of the archive commands. + if test "$module" = yes && test -n "$module_cmds" ; then + if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then + eval test_cmds=\"$module_expsym_cmds\" + cmds=$module_expsym_cmds + else + eval test_cmds=\"$module_cmds\" + cmds=$module_cmds + fi + else + if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then + eval test_cmds=\"$archive_expsym_cmds\" + cmds=$archive_expsym_cmds + else + eval test_cmds=\"$archive_cmds\" + cmds=$archive_cmds + fi + fi + + if test "X$skipped_export" != "X:" && + len=`expr "X$test_cmds" : ".*" 2>/dev/null` && + test "$len" -le "$max_cmd_len" || test "$max_cmd_len" -le -1; then + : + else + # The command line is too long to link in one step, link piecewise. + $echo "creating reloadable object files..." + + # Save the value of $output and $libobjs because we want to + # use them later. If we have whole_archive_flag_spec, we + # want to use save_libobjs as it was before + # whole_archive_flag_spec was expanded, because we can't + # assume the linker understands whole_archive_flag_spec. + # This may have to be revisited, in case too many + # convenience libraries get linked in and end up exceeding + # the spec. + if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then + save_libobjs=$libobjs + fi + save_output=$output + output_la=`$echo "X$output" | $Xsed -e "$basename"` + + # Clear the reloadable object creation command queue and + # initialize k to one. + test_cmds= + concat_cmds= + objlist= + delfiles= + last_robj= + k=1 + output=$output_objdir/$output_la-${k}.$objext + # Loop over the list of objects to be linked. + for obj in $save_libobjs + do + eval test_cmds=\"$reload_cmds $objlist $last_robj\" + if test "X$objlist" = X || + { len=`expr "X$test_cmds" : ".*" 2>/dev/null` && + test "$len" -le "$max_cmd_len"; }; then + objlist="$objlist $obj" + else + # The command $test_cmds is almost too long, add a + # command to the queue. + if test "$k" -eq 1 ; then + # The first file doesn't have a previous command to add. + eval concat_cmds=\"$reload_cmds $objlist $last_robj\" + else + # All subsequent reloadable object files will link in + # the last one created. + eval concat_cmds=\"\$concat_cmds~$reload_cmds $objlist $last_robj\" + fi + last_robj=$output_objdir/$output_la-${k}.$objext + k=`expr $k + 1` + output=$output_objdir/$output_la-${k}.$objext + objlist=$obj + len=1 + fi + done + # Handle the remaining objects by creating one last + # reloadable object file. All subsequent reloadable object + # files will link in the last one created. + test -z "$concat_cmds" || concat_cmds=$concat_cmds~ + eval concat_cmds=\"\${concat_cmds}$reload_cmds $objlist $last_robj\" + + if ${skipped_export-false}; then + $show "generating symbol list for \`$libname.la'" + export_symbols="$output_objdir/$libname.exp" + $run $rm $export_symbols + libobjs=$output + # Append the command to create the export file. + eval concat_cmds=\"\$concat_cmds~$export_symbols_cmds\" + fi + + # Set up a command to remove the reloadable object files + # after they are used. + i=0 + while test "$i" -lt "$k" + do + i=`expr $i + 1` + delfiles="$delfiles $output_objdir/$output_la-${i}.$objext" + done + + $echo "creating a temporary reloadable object file: $output" + + # Loop through the commands generated above and execute them. + save_ifs="$IFS"; IFS='~' + for cmd in $concat_cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + + libobjs=$output + # Restore the value of output. + output=$save_output + + if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then + eval libobjs=\"\$libobjs $whole_archive_flag_spec\" + fi + # Expand the library linking commands again to reset the + # value of $libobjs for piecewise linking. + + # Do each of the archive commands. + if test "$module" = yes && test -n "$module_cmds" ; then + if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then + cmds=$module_expsym_cmds + else + cmds=$module_cmds + fi + else + if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then + cmds=$archive_expsym_cmds + else + cmds=$archive_cmds + fi + fi + + # Append the command to remove the reloadable object files + # to the just-reset $cmds. + eval cmds=\"\$cmds~\$rm $delfiles\" + fi + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" || { + lt_exit=$? + + # Restore the uninstalled library and exit + if test "$mode" = relink; then + $run eval '(cd $output_objdir && $rm ${realname}T && $mv ${realname}U $realname)' + fi + + exit $lt_exit + } + done + IFS="$save_ifs" + + # Restore the uninstalled library and exit + if test "$mode" = relink; then + $run eval '(cd $output_objdir && $rm ${realname}T && $mv $realname ${realname}T && $mv "$realname"U $realname)' || exit $? + + if test -n "$convenience"; then + if test -z "$whole_archive_flag_spec"; then + $show "${rm}r $gentop" + $run ${rm}r "$gentop" + fi + fi + + exit $EXIT_SUCCESS + fi + + # Create links to the real library. + for linkname in $linknames; do + if test "$realname" != "$linkname"; then + $show "(cd $output_objdir && $rm $linkname && $LN_S $realname $linkname)" + $run eval '(cd $output_objdir && $rm $linkname && $LN_S $realname $linkname)' || exit $? + fi + done + + # If -module or -export-dynamic was specified, set the dlname. + if test "$module" = yes || test "$export_dynamic" = yes; then + # On all known operating systems, these are identical. + dlname="$soname" + fi + fi + ;; + + obj) + case " $deplibs" in + *\ -l* | *\ -L*) + $echo "$modename: warning: \`-l' and \`-L' are ignored for objects" 1>&2 ;; + esac + + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + $echo "$modename: warning: \`-dlopen' is ignored for objects" 1>&2 + fi + + if test -n "$rpath"; then + $echo "$modename: warning: \`-rpath' is ignored for objects" 1>&2 + fi + + if test -n "$xrpath"; then + $echo "$modename: warning: \`-R' is ignored for objects" 1>&2 + fi + + if test -n "$vinfo"; then + $echo "$modename: warning: \`-version-info' is ignored for objects" 1>&2 + fi + + if test -n "$release"; then + $echo "$modename: warning: \`-release' is ignored for objects" 1>&2 + fi + + case $output in + *.lo) + if test -n "$objs$old_deplibs"; then + $echo "$modename: cannot build library object \`$output' from non-libtool objects" 1>&2 + exit $EXIT_FAILURE + fi + libobj="$output" + obj=`$echo "X$output" | $Xsed -e "$lo2o"` + ;; + *) + libobj= + obj="$output" + ;; + esac + + # Delete the old objects. + $run $rm $obj $libobj + + # Objects from convenience libraries. This assumes + # single-version convenience libraries. Whenever we create + # different ones for PIC/non-PIC, this we'll have to duplicate + # the extraction. + reload_conv_objs= + gentop= + # reload_cmds runs $LD directly, so let us get rid of + # -Wl from whole_archive_flag_spec and hope we can get by with + # turning comma into space.. + wl= + + if test -n "$convenience"; then + if test -n "$whole_archive_flag_spec"; then + eval tmp_whole_archive_flags=\"$whole_archive_flag_spec\" + reload_conv_objs=$reload_objs\ `$echo "X$tmp_whole_archive_flags" | $Xsed -e 's|,| |g'` + else + gentop="$output_objdir/${obj}x" + generated="$generated $gentop" + + func_extract_archives $gentop $convenience + reload_conv_objs="$reload_objs $func_extract_archives_result" + fi + fi + + # Create the old-style object. + reload_objs="$objs$old_deplibs "`$echo "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}$'/d' -e '/\.lib$/d' -e "$lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test + + output="$obj" + cmds=$reload_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + + # Exit if we aren't doing a library object file. + if test -z "$libobj"; then + if test -n "$gentop"; then + $show "${rm}r $gentop" + $run ${rm}r $gentop + fi + + exit $EXIT_SUCCESS + fi + + if test "$build_libtool_libs" != yes; then + if test -n "$gentop"; then + $show "${rm}r $gentop" + $run ${rm}r $gentop + fi + + # Create an invalid libtool object if no PIC, so that we don't + # accidentally link it into a program. + # $show "echo timestamp > $libobj" + # $run eval "echo timestamp > $libobj" || exit $? + exit $EXIT_SUCCESS + fi + + if test -n "$pic_flag" || test "$pic_mode" != default; then + # Only do commands if we really have different PIC objects. + reload_objs="$libobjs $reload_conv_objs" + output="$libobj" + cmds=$reload_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + fi + + if test -n "$gentop"; then + $show "${rm}r $gentop" + $run ${rm}r $gentop + fi + + exit $EXIT_SUCCESS + ;; + + prog) + case $host in + *cygwin*) output=`$echo $output | ${SED} -e 's,.exe$,,;s,$,.exe,'` ;; + esac + if test -n "$vinfo"; then + $echo "$modename: warning: \`-version-info' is ignored for programs" 1>&2 + fi + + if test -n "$release"; then + $echo "$modename: warning: \`-release' is ignored for programs" 1>&2 + fi + + if test "$preload" = yes; then + if test "$dlopen_support" = unknown && test "$dlopen_self" = unknown && + test "$dlopen_self_static" = unknown; then + $echo "$modename: warning: \`AC_LIBTOOL_DLOPEN' not used. Assuming no dlopen support." + fi + fi + + case $host in + *-*-rhapsody* | *-*-darwin1.[012]) + # On Rhapsody replace the C library is the System framework + compile_deplibs=`$echo "X $compile_deplibs" | $Xsed -e 's/ -lc / -framework System /'` + finalize_deplibs=`$echo "X $finalize_deplibs" | $Xsed -e 's/ -lc / -framework System /'` + ;; + esac + + case $host in + *darwin*) + # Don't allow lazy linking, it breaks C++ global constructors + if test "$tagname" = CXX ; then + compile_command="$compile_command ${wl}-bind_at_load" + finalize_command="$finalize_command ${wl}-bind_at_load" + fi + ;; + esac + + + # move library search paths that coincide with paths to not yet + # installed libraries to the beginning of the library search list + new_libs= + for path in $notinst_path; do + case " $new_libs " in + *" -L$path/$objdir "*) ;; + *) + case " $compile_deplibs " in + *" -L$path/$objdir "*) + new_libs="$new_libs -L$path/$objdir" ;; + esac + ;; + esac + done + for deplib in $compile_deplibs; do + case $deplib in + -L*) + case " $new_libs " in + *" $deplib "*) ;; + *) new_libs="$new_libs $deplib" ;; + esac + ;; + *) new_libs="$new_libs $deplib" ;; + esac + done + compile_deplibs="$new_libs" + + + compile_command="$compile_command $compile_deplibs" + finalize_command="$finalize_command $finalize_deplibs" + + if test -n "$rpath$xrpath"; then + # If the user specified any rpath flags, then add them. + for libdir in $rpath $xrpath; do + # This is the magic to use -rpath. + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" ;; + esac + done + fi + + # Now hardcode the library paths + rpath= + hardcode_libdirs= + for libdir in $compile_rpath $finalize_rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + rpath="$rpath $flag" + fi + elif test -n "$runpath_var"; then + case "$perm_rpath " in + *" $libdir "*) ;; + *) perm_rpath="$perm_rpath $libdir" ;; + esac + fi + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*) + testbindir=`$echo "X$libdir" | $Xsed -e 's*/lib$*/bin*'` + case :$dllsearchpath: in + *":$libdir:"*) ;; + *) dllsearchpath="$dllsearchpath:$libdir";; + esac + case :$dllsearchpath: in + *":$testbindir:"*) ;; + *) dllsearchpath="$dllsearchpath:$testbindir";; + esac + ;; + esac + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + eval rpath=\" $hardcode_libdir_flag_spec\" + fi + compile_rpath="$rpath" + + rpath= + hardcode_libdirs= + for libdir in $finalize_rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + rpath="$rpath $flag" + fi + elif test -n "$runpath_var"; then + case "$finalize_perm_rpath " in + *" $libdir "*) ;; + *) finalize_perm_rpath="$finalize_perm_rpath $libdir" ;; + esac + fi + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + eval rpath=\" $hardcode_libdir_flag_spec\" + fi + finalize_rpath="$rpath" + + if test -n "$libobjs" && test "$build_old_libs" = yes; then + # Transform all the library objects into standard objects. + compile_command=`$echo "X$compile_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + finalize_command=`$echo "X$finalize_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + fi + + dlsyms= + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + if test -n "$NM" && test -n "$global_symbol_pipe"; then + dlsyms="${outputname}S.c" + else + $echo "$modename: not configured to extract global symbols from dlpreopened files" 1>&2 + fi + fi + + if test -n "$dlsyms"; then + case $dlsyms in + "") ;; + *.c) + # Discover the nlist of each of the dlfiles. + nlist="$output_objdir/${outputname}.nm" + + $show "$rm $nlist ${nlist}S ${nlist}T" + $run $rm "$nlist" "${nlist}S" "${nlist}T" + + # Parse the name list into a source file. + $show "creating $output_objdir/$dlsyms" + + test -z "$run" && $echo > "$output_objdir/$dlsyms" "\ +/* $dlsyms - symbol resolution table for \`$outputname' dlsym emulation. */ +/* Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP */ + +#ifdef __cplusplus +extern \"C\" { +#endif + +/* Prevent the only kind of declaration conflicts we can make. */ +#define lt_preloaded_symbols some_other_symbol + +/* External symbol declarations for the compiler. */\ +" + + if test "$dlself" = yes; then + $show "generating symbol list for \`$output'" + + test -z "$run" && $echo ': @PROGRAM@ ' > "$nlist" + + # Add our own program objects to the symbol list. + progfiles=`$echo "X$objs$old_deplibs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + for arg in $progfiles; do + $show "extracting global C symbols from \`$arg'" + $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'" + done + + if test -n "$exclude_expsyms"; then + $run eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T' + $run eval '$mv "$nlist"T "$nlist"' + fi + + if test -n "$export_symbols_regex"; then + $run eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T' + $run eval '$mv "$nlist"T "$nlist"' + fi + + # Prepare the list of exported symbols + if test -z "$export_symbols"; then + export_symbols="$output_objdir/$outputname.exp" + $run $rm $export_symbols + $run eval "${SED} -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"' + case $host in + *cygwin* | *mingw* ) + $run eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' + $run eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"' + ;; + esac + else + $run eval "${SED} -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"' + $run eval 'grep -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T' + $run eval 'mv "$nlist"T "$nlist"' + case $host in + *cygwin* | *mingw* ) + $run eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' + $run eval 'cat "$nlist" >> "$output_objdir/$outputname.def"' + ;; + esac + fi + fi + + for arg in $dlprefiles; do + $show "extracting global C symbols from \`$arg'" + name=`$echo "$arg" | ${SED} -e 's%^.*/%%'` + $run eval '$echo ": $name " >> "$nlist"' + $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'" + done + + if test -z "$run"; then + # Make sure we have at least an empty file. + test -f "$nlist" || : > "$nlist" + + if test -n "$exclude_expsyms"; then + $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T + $mv "$nlist"T "$nlist" + fi + + # Try sorting and uniquifying the output. + if grep -v "^: " < "$nlist" | + if sort -k 3 /dev/null 2>&1; then + sort -k 3 + else + sort +2 + fi | + uniq > "$nlist"S; then + : + else + grep -v "^: " < "$nlist" > "$nlist"S + fi + + if test -f "$nlist"S; then + eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$dlsyms"' + else + $echo '/* NONE */' >> "$output_objdir/$dlsyms" + fi + + $echo >> "$output_objdir/$dlsyms" "\ + +#undef lt_preloaded_symbols + +#if defined (__STDC__) && __STDC__ +# define lt_ptr void * +#else +# define lt_ptr char * +# define const +#endif + +/* The mapping between symbol names and symbols. */ +" + + case $host in + *cygwin* | *mingw* ) + $echo >> "$output_objdir/$dlsyms" "\ +/* DATA imports from DLLs on WIN32 can't be const, because + runtime relocations are performed -- see ld's documentation + on pseudo-relocs */ +struct { +" + ;; + * ) + $echo >> "$output_objdir/$dlsyms" "\ +const struct { +" + ;; + esac + + + $echo >> "$output_objdir/$dlsyms" "\ + const char *name; + lt_ptr address; +} +lt_preloaded_symbols[] = +{\ +" + + eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$dlsyms" + + $echo >> "$output_objdir/$dlsyms" "\ + {0, (lt_ptr) 0} +}; + +/* This works around a problem in FreeBSD linker */ +#ifdef FREEBSD_WORKAROUND +static const void *lt_preloaded_setup() { + return lt_preloaded_symbols; +} +#endif + +#ifdef __cplusplus +} +#endif\ +" + fi + + pic_flag_for_symtable= + case $host in + # compiling the symbol table file with pic_flag works around + # a FreeBSD bug that causes programs to crash when -lm is + # linked before any other PIC object. But we must not use + # pic_flag when linking with -static. The problem exists in + # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1. + *-*-freebsd2*|*-*-freebsd3.0*|*-*-freebsdelf3.0*) + case "$compile_command " in + *" -static "*) ;; + *) pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND";; + esac;; + *-*-hpux*) + case "$compile_command " in + *" -static "*) ;; + *) pic_flag_for_symtable=" $pic_flag";; + esac + esac + + # Now compile the dynamic symbol file. + $show "(cd $output_objdir && $LTCC $LTCFLAGS -c$no_builtin_flag$pic_flag_for_symtable \"$dlsyms\")" + $run eval '(cd $output_objdir && $LTCC $LTCFLAGS -c$no_builtin_flag$pic_flag_for_symtable "$dlsyms")' || exit $? + + # Clean up the generated files. + $show "$rm $output_objdir/$dlsyms $nlist ${nlist}S ${nlist}T" + $run $rm "$output_objdir/$dlsyms" "$nlist" "${nlist}S" "${nlist}T" + + # Transform the symbol file into the correct name. + case $host in + *cygwin* | *mingw* ) + if test -f "$output_objdir/${outputname}.def" ; then + compile_command=`$echo "X$compile_command" | $SP2NL | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}.def $output_objdir/${outputname}S.${objext}%" | $NL2SP` + finalize_command=`$echo "X$finalize_command" | $SP2NL | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}.def $output_objdir/${outputname}S.${objext}%" | $NL2SP` + else + compile_command=`$echo "X$compile_command" | $SP2NL | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%" | $NL2SP` + finalize_command=`$echo "X$finalize_command" | $SP2NL | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%" | $NL2SP` + fi + ;; + * ) + compile_command=`$echo "X$compile_command" | $SP2NL | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%" | $NL2SP` + finalize_command=`$echo "X$finalize_command" | $SP2NL | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%" | $NL2SP` + ;; + esac + ;; + *) + $echo "$modename: unknown suffix for \`$dlsyms'" 1>&2 + exit $EXIT_FAILURE + ;; + esac + else + # We keep going just in case the user didn't refer to + # lt_preloaded_symbols. The linker will fail if global_symbol_pipe + # really was required. + + # Nullify the symbol file. + compile_command=`$echo "X$compile_command" | $SP2NL | $Xsed -e "s% @SYMFILE@%%" | $NL2SP` + finalize_command=`$echo "X$finalize_command" | $SP2NL | $Xsed -e "s% @SYMFILE@%%" | $NL2SP` + fi + + if test "$need_relink" = no || test "$build_libtool_libs" != yes; then + # Replace the output file specification. + compile_command=`$echo "X$compile_command" | $SP2NL | $Xsed -e 's%@OUTPUT@%'"$output"'%g' | $NL2SP` + link_command="$compile_command$compile_rpath" + + # We have no uninstalled library dependencies, so finalize right now. + $show "$link_command" + $run eval "$link_command" + exit_status=$? + + # Delete the generated files. + if test -n "$dlsyms"; then + $show "$rm $output_objdir/${outputname}S.${objext}" + $run $rm "$output_objdir/${outputname}S.${objext}" + fi + + exit $exit_status + fi + + if test -n "$shlibpath_var"; then + # We should set the shlibpath_var + rpath= + for dir in $temp_rpath; do + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) + # Absolute path. + rpath="$rpath$dir:" + ;; + *) + # Relative path: add a thisdir entry. + rpath="$rpath\$thisdir/$dir:" + ;; + esac + done + temp_rpath="$rpath" + fi + + if test -n "$compile_shlibpath$finalize_shlibpath"; then + compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command" + fi + if test -n "$finalize_shlibpath"; then + finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command" + fi + + compile_var= + finalize_var= + if test -n "$runpath_var"; then + if test -n "$perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $perm_rpath; do + rpath="$rpath$dir:" + done + compile_var="$runpath_var=\"$rpath\$$runpath_var\" " + fi + if test -n "$finalize_perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $finalize_perm_rpath; do + rpath="$rpath$dir:" + done + finalize_var="$runpath_var=\"$rpath\$$runpath_var\" " + fi + fi + + if test "$no_install" = yes; then + # We don't need to create a wrapper script. + link_command="$compile_var$compile_command$compile_rpath" + # Replace the output file specification. + link_command=`$echo "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'` + # Delete the old output file. + $run $rm $output + # Link the executable and exit + $show "$link_command" + $run eval "$link_command" || exit $? + exit $EXIT_SUCCESS + fi + + if test "$hardcode_action" = relink; then + # Fast installation is not supported + link_command="$compile_var$compile_command$compile_rpath" + relink_command="$finalize_var$finalize_command$finalize_rpath" + + $echo "$modename: warning: this platform does not like uninstalled shared libraries" 1>&2 + $echo "$modename: \`$output' will be relinked during installation" 1>&2 + else + if test "$fast_install" != no; then + link_command="$finalize_var$compile_command$finalize_rpath" + if test "$fast_install" = yes; then + relink_command=`$echo "X$compile_var$compile_command$compile_rpath" | $SP2NL | $Xsed -e 's%@OUTPUT@%\$progdir/\$file%g' | $NL2SP` + else + # fast_install is set to needless + relink_command= + fi + else + link_command="$compile_var$compile_command$compile_rpath" + relink_command="$finalize_var$finalize_command$finalize_rpath" + fi + fi + + # Replace the output file specification. + link_command=`$echo "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'` + + # Delete the old output files. + $run $rm $output $output_objdir/$outputname $output_objdir/lt-$outputname + + $show "$link_command" + $run eval "$link_command" || exit $? + + # Now create the wrapper script. + $show "creating $output" + + # Quote the relink command for shipping. + if test -n "$relink_command"; then + # Preserve any variables that may affect compiler behavior + for var in $variables_saved_for_relink; do + if eval test -z \"\${$var+set}\"; then + relink_command="{ test -z \"\${$var+set}\" || unset $var || { $var=; export $var; }; }; $relink_command" + elif eval var_value=\$$var; test -z "$var_value"; then + relink_command="$var=; export $var; $relink_command" + else + var_value=`$echo "X$var_value" | $Xsed -e "$sed_quote_subst"` + relink_command="$var=\"$var_value\"; export $var; $relink_command" + fi + done + relink_command="(cd `pwd`; $relink_command)" + relink_command=`$echo "X$relink_command" | $SP2NL | $Xsed -e "$sed_quote_subst" | $NL2SP` + fi + + # Quote $echo for shipping. + if test "X$echo" = "X$SHELL $progpath --fallback-echo"; then + case $progpath in + [\\/]* | [A-Za-z]:[\\/]*) qecho="$SHELL $progpath --fallback-echo";; + *) qecho="$SHELL `pwd`/$progpath --fallback-echo";; + esac + qecho=`$echo "X$qecho" | $Xsed -e "$sed_quote_subst"` + else + qecho=`$echo "X$echo" | $Xsed -e "$sed_quote_subst"` + fi + + # Only actually do things if our run command is non-null. + if test -z "$run"; then + # win32 will think the script is a binary if it has + # a .exe suffix, so we strip it off here. + case $output in + *.exe) output=`$echo $output|${SED} 's,.exe$,,'` ;; + esac + # test for cygwin because mv fails w/o .exe extensions + case $host in + *cygwin*) + exeext=.exe + outputname=`$echo $outputname|${SED} 's,.exe$,,'` ;; + *) exeext= ;; + esac + case $host in + *cygwin* | *mingw* ) + output_name=`basename $output` + output_path=`dirname $output` + cwrappersource="$output_path/$objdir/lt-$output_name.c" + cwrapper="$output_path/$output_name.exe" + $rm $cwrappersource $cwrapper + trap "$rm $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15 + + cat > $cwrappersource <> $cwrappersource<<"EOF" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(PATH_MAX) +# define LT_PATHMAX PATH_MAX +#elif defined(MAXPATHLEN) +# define LT_PATHMAX MAXPATHLEN +#else +# define LT_PATHMAX 1024 +#endif + +#ifndef DIR_SEPARATOR +# define DIR_SEPARATOR '/' +# define PATH_SEPARATOR ':' +#endif + +#if defined (_WIN32) || defined (__MSDOS__) || defined (__DJGPP__) || \ + defined (__OS2__) +# define HAVE_DOS_BASED_FILE_SYSTEM +# ifndef DIR_SEPARATOR_2 +# define DIR_SEPARATOR_2 '\\' +# endif +# ifndef PATH_SEPARATOR_2 +# define PATH_SEPARATOR_2 ';' +# endif +#endif + +#ifndef DIR_SEPARATOR_2 +# define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR) +#else /* DIR_SEPARATOR_2 */ +# define IS_DIR_SEPARATOR(ch) \ + (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2)) +#endif /* DIR_SEPARATOR_2 */ + +#ifndef PATH_SEPARATOR_2 +# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR) +#else /* PATH_SEPARATOR_2 */ +# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2) +#endif /* PATH_SEPARATOR_2 */ + +#define XMALLOC(type, num) ((type *) xmalloc ((num) * sizeof(type))) +#define XFREE(stale) do { \ + if (stale) { free ((void *) stale); stale = 0; } \ +} while (0) + +/* -DDEBUG is fairly common in CFLAGS. */ +#undef DEBUG +#if defined DEBUGWRAPPER +# define DEBUG(format, ...) fprintf(stderr, format, __VA_ARGS__) +#else +# define DEBUG(format, ...) +#endif + +const char *program_name = NULL; + +void * xmalloc (size_t num); +char * xstrdup (const char *string); +const char * base_name (const char *name); +char * find_executable(const char *wrapper); +int check_executable(const char *path); +char * strendzap(char *str, const char *pat); +void lt_fatal (const char *message, ...); + +int +main (int argc, char *argv[]) +{ + char **newargz; + int i; + + program_name = (char *) xstrdup (base_name (argv[0])); + DEBUG("(main) argv[0] : %s\n",argv[0]); + DEBUG("(main) program_name : %s\n",program_name); + newargz = XMALLOC(char *, argc+2); +EOF + + cat >> $cwrappersource <> $cwrappersource <<"EOF" + newargz[1] = find_executable(argv[0]); + if (newargz[1] == NULL) + lt_fatal("Couldn't find %s", argv[0]); + DEBUG("(main) found exe at : %s\n",newargz[1]); + /* we know the script has the same name, without the .exe */ + /* so make sure newargz[1] doesn't end in .exe */ + strendzap(newargz[1],".exe"); + for (i = 1; i < argc; i++) + newargz[i+1] = xstrdup(argv[i]); + newargz[argc+1] = NULL; + + for (i=0; i> $cwrappersource <> $cwrappersource <> $cwrappersource <<"EOF" + return 127; +} + +void * +xmalloc (size_t num) +{ + void * p = (void *) malloc (num); + if (!p) + lt_fatal ("Memory exhausted"); + + return p; +} + +char * +xstrdup (const char *string) +{ + return string ? strcpy ((char *) xmalloc (strlen (string) + 1), string) : NULL +; +} + +const char * +base_name (const char *name) +{ + const char *base; + +#if defined (HAVE_DOS_BASED_FILE_SYSTEM) + /* Skip over the disk name in MSDOS pathnames. */ + if (isalpha ((unsigned char)name[0]) && name[1] == ':') + name += 2; +#endif + + for (base = name; *name; name++) + if (IS_DIR_SEPARATOR (*name)) + base = name + 1; + return base; +} + +int +check_executable(const char * path) +{ + struct stat st; + + DEBUG("(check_executable) : %s\n", path ? (*path ? path : "EMPTY!") : "NULL!"); + if ((!path) || (!*path)) + return 0; + + if ((stat (path, &st) >= 0) && + ( + /* MinGW & native WIN32 do not support S_IXOTH or S_IXGRP */ +#if defined (S_IXOTH) + ((st.st_mode & S_IXOTH) == S_IXOTH) || +#endif +#if defined (S_IXGRP) + ((st.st_mode & S_IXGRP) == S_IXGRP) || +#endif + ((st.st_mode & S_IXUSR) == S_IXUSR)) + ) + return 1; + else + return 0; +} + +/* Searches for the full path of the wrapper. Returns + newly allocated full path name if found, NULL otherwise */ +char * +find_executable (const char* wrapper) +{ + int has_slash = 0; + const char* p; + const char* p_next; + /* static buffer for getcwd */ + char tmp[LT_PATHMAX + 1]; + int tmp_len; + char* concat_name; + + DEBUG("(find_executable) : %s\n", wrapper ? (*wrapper ? wrapper : "EMPTY!") : "NULL!"); + + if ((wrapper == NULL) || (*wrapper == '\0')) + return NULL; + + /* Absolute path? */ +#if defined (HAVE_DOS_BASED_FILE_SYSTEM) + if (isalpha ((unsigned char)wrapper[0]) && wrapper[1] == ':') + { + concat_name = xstrdup (wrapper); + if (check_executable(concat_name)) + return concat_name; + XFREE(concat_name); + } + else + { +#endif + if (IS_DIR_SEPARATOR (wrapper[0])) + { + concat_name = xstrdup (wrapper); + if (check_executable(concat_name)) + return concat_name; + XFREE(concat_name); + } +#if defined (HAVE_DOS_BASED_FILE_SYSTEM) + } +#endif + + for (p = wrapper; *p; p++) + if (*p == '/') + { + has_slash = 1; + break; + } + if (!has_slash) + { + /* no slashes; search PATH */ + const char* path = getenv ("PATH"); + if (path != NULL) + { + for (p = path; *p; p = p_next) + { + const char* q; + size_t p_len; + for (q = p; *q; q++) + if (IS_PATH_SEPARATOR(*q)) + break; + p_len = q - p; + p_next = (*q == '\0' ? q : q + 1); + if (p_len == 0) + { + /* empty path: current directory */ + if (getcwd (tmp, LT_PATHMAX) == NULL) + lt_fatal ("getcwd failed"); + tmp_len = strlen(tmp); + concat_name = XMALLOC(char, tmp_len + 1 + strlen(wrapper) + 1); + memcpy (concat_name, tmp, tmp_len); + concat_name[tmp_len] = '/'; + strcpy (concat_name + tmp_len + 1, wrapper); + } + else + { + concat_name = XMALLOC(char, p_len + 1 + strlen(wrapper) + 1); + memcpy (concat_name, p, p_len); + concat_name[p_len] = '/'; + strcpy (concat_name + p_len + 1, wrapper); + } + if (check_executable(concat_name)) + return concat_name; + XFREE(concat_name); + } + } + /* not found in PATH; assume curdir */ + } + /* Relative path | not found in path: prepend cwd */ + if (getcwd (tmp, LT_PATHMAX) == NULL) + lt_fatal ("getcwd failed"); + tmp_len = strlen(tmp); + concat_name = XMALLOC(char, tmp_len + 1 + strlen(wrapper) + 1); + memcpy (concat_name, tmp, tmp_len); + concat_name[tmp_len] = '/'; + strcpy (concat_name + tmp_len + 1, wrapper); + + if (check_executable(concat_name)) + return concat_name; + XFREE(concat_name); + return NULL; +} + +char * +strendzap(char *str, const char *pat) +{ + size_t len, patlen; + + assert(str != NULL); + assert(pat != NULL); + + len = strlen(str); + patlen = strlen(pat); + + if (patlen <= len) + { + str += len - patlen; + if (strcmp(str, pat) == 0) + *str = '\0'; + } + return str; +} + +static void +lt_error_core (int exit_status, const char * mode, + const char * message, va_list ap) +{ + fprintf (stderr, "%s: %s: ", program_name, mode); + vfprintf (stderr, message, ap); + fprintf (stderr, ".\n"); + + if (exit_status >= 0) + exit (exit_status); +} + +void +lt_fatal (const char *message, ...) +{ + va_list ap; + va_start (ap, message); + lt_error_core (EXIT_FAILURE, "FATAL", message, ap); + va_end (ap); +} +EOF + # we should really use a build-platform specific compiler + # here, but OTOH, the wrappers (shell script and this C one) + # are only useful if you want to execute the "real" binary. + # Since the "real" binary is built for $host, then this + # wrapper might as well be built for $host, too. + $run $LTCC $LTCFLAGS -s -o $cwrapper $cwrappersource + ;; + esac + $rm $output + trap "$rm $output; exit $EXIT_FAILURE" 1 2 15 + + $echo > $output "\ +#! $SHELL + +# $output - temporary wrapper script for $objdir/$outputname +# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP +# +# The $output program cannot be directly executed until all the libtool +# libraries that it depends on are installed. +# +# This wrapper script should never be moved out of the build directory. +# If it is, it will not operate correctly. + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +Xsed='${SED} -e 1s/^X//' +sed_quote_subst='$sed_quote_subst' + +# Be Bourne compatible (taken from Autoconf:_AS_BOURNE_COMPATIBLE). +if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs 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 +BIN_SH=xpg4; export BIN_SH # for Tru64 +DUALCASE=1; export DUALCASE # for MKS sh + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +relink_command=\"$relink_command\" + +# This environment variable determines our operation mode. +if test \"\$libtool_install_magic\" = \"$magic\"; then + # install mode needs the following variable: + notinst_deplibs='$notinst_deplibs' +else + # When we are sourced in execute mode, \$file and \$echo are already set. + if test \"\$libtool_execute_magic\" != \"$magic\"; then + echo=\"$qecho\" + file=\"\$0\" + # Make sure echo works. + if test \"X\$1\" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift + elif test \"X\`(\$echo '\t') 2>/dev/null\`\" = 'X\t'; then + # Yippee, \$echo works! + : + else + # Restart under the correct shell, and then maybe \$echo will work. + exec $SHELL \"\$0\" --no-reexec \${1+\"\$@\"} + fi + fi\ +" + $echo >> $output "\ + + # Find the directory that this script lives in. + thisdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*$%%'\` + test \"x\$thisdir\" = \"x\$file\" && thisdir=. + + # Follow symbolic links until we get to the real thisdir. + file=\`ls -ld \"\$file\" | ${SED} -n 's/.*-> //p'\` + while test -n \"\$file\"; do + destdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*\$%%'\` + + # If there was a directory component, then change thisdir. + if test \"x\$destdir\" != \"x\$file\"; then + case \"\$destdir\" in + [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;; + *) thisdir=\"\$thisdir/\$destdir\" ;; + esac + fi + + file=\`\$echo \"X\$file\" | \$Xsed -e 's%^.*/%%'\` + file=\`ls -ld \"\$thisdir/\$file\" | ${SED} -n 's/.*-> //p'\` + done + + # Try to get the absolute directory name. + absdir=\`cd \"\$thisdir\" && pwd\` + test -n \"\$absdir\" && thisdir=\"\$absdir\" +" + + if test "$fast_install" = yes; then + $echo >> $output "\ + program=lt-'$outputname'$exeext + progdir=\"\$thisdir/$objdir\" + + if test ! -f \"\$progdir/\$program\" || \\ + { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | ${SED} 1q\`; \\ + test \"X\$file\" != \"X\$progdir/\$program\"; }; then + + file=\"\$\$-\$program\" + + if test ! -d \"\$progdir\"; then + $mkdir \"\$progdir\" + else + $rm \"\$progdir/\$file\" + fi" + + $echo >> $output "\ + + # relink executable if necessary + if test -n \"\$relink_command\"; then + if relink_command_output=\`eval \$relink_command 2>&1\`; then : + else + $echo \"\$relink_command_output\" >&2 + $rm \"\$progdir/\$file\" + exit $EXIT_FAILURE + fi + fi + + $mv \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null || + { $rm \"\$progdir/\$program\"; + $mv \"\$progdir/\$file\" \"\$progdir/\$program\"; } + $rm \"\$progdir/\$file\" + fi" + else + $echo >> $output "\ + program='$outputname' + progdir=\"\$thisdir/$objdir\" +" + fi + + $echo >> $output "\ + + if test -f \"\$progdir/\$program\"; then" + + # Export our shlibpath_var if we have one. + if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then + $echo >> $output "\ + # Add our own library path to $shlibpath_var + $shlibpath_var=\"$temp_rpath\$$shlibpath_var\" + + # Some systems cannot cope with colon-terminated $shlibpath_var + # The second colon is a workaround for a bug in BeOS R4 sed + $shlibpath_var=\`\$echo \"X\$$shlibpath_var\" | \$Xsed -e 's/::*\$//'\` + + export $shlibpath_var +" + fi + + # fixup the dll searchpath if we need to. + if test -n "$dllsearchpath"; then + $echo >> $output "\ + # Add the dll search path components to the executable PATH + PATH=$dllsearchpath:\$PATH +" + fi + + $echo >> $output "\ + if test \"\$libtool_execute_magic\" != \"$magic\"; then + # Run the actual program with our arguments. +" + case $host in + # Backslashes separate directories on plain windows + *-*-mingw | *-*-os2*) + $echo >> $output "\ + exec \"\$progdir\\\\\$program\" \${1+\"\$@\"} +" + ;; + + *) + $echo >> $output "\ + exec \"\$progdir/\$program\" \${1+\"\$@\"} +" + ;; + esac + $echo >> $output "\ + \$echo \"\$0: cannot exec \$program \$*\" + exit $EXIT_FAILURE + fi + else + # The program doesn't exist. + \$echo \"\$0: error: \\\`\$progdir/\$program' does not exist\" 1>&2 + \$echo \"This script is just a wrapper for \$program.\" 1>&2 + $echo \"See the $PACKAGE documentation for more information.\" 1>&2 + exit $EXIT_FAILURE + fi +fi\ +" + chmod +x $output + fi + exit $EXIT_SUCCESS + ;; + esac + + # See if we need to build an old-fashioned archive. + for oldlib in $oldlibs; do + + if test "$build_libtool_libs" = convenience; then + oldobjs="$libobjs_save" + addlibs="$convenience" + build_libtool_libs=no + else + if test "$build_libtool_libs" = module; then + oldobjs="$libobjs_save" + build_libtool_libs=no + else + oldobjs="$old_deplibs $non_pic_objects" + fi + addlibs="$old_convenience" + fi + + if test -n "$addlibs"; then + gentop="$output_objdir/${outputname}x" + generated="$generated $gentop" + + func_extract_archives $gentop $addlibs + oldobjs="$oldobjs $func_extract_archives_result" + fi + + # Do each command in the archive commands. + if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then + cmds=$old_archive_from_new_cmds + else + # POSIX demands no paths to be encoded in archives. We have + # to avoid creating archives with duplicate basenames if we + # might have to extract them afterwards, e.g., when creating a + # static archive out of a convenience library, or when linking + # the entirety of a libtool archive into another (currently + # not supported by libtool). + if (for obj in $oldobjs + do + $echo "X$obj" | $Xsed -e 's%^.*/%%' + done | sort | sort -uc >/dev/null 2>&1); then + : + else + $echo "copying selected object files to avoid basename conflicts..." + + if test -z "$gentop"; then + gentop="$output_objdir/${outputname}x" + generated="$generated $gentop" + + $show "${rm}r $gentop" + $run ${rm}r "$gentop" + $show "$mkdir $gentop" + $run $mkdir "$gentop" + exit_status=$? + if test "$exit_status" -ne 0 && test ! -d "$gentop"; then + exit $exit_status + fi + fi + + save_oldobjs=$oldobjs + oldobjs= + counter=1 + for obj in $save_oldobjs + do + objbase=`$echo "X$obj" | $Xsed -e 's%^.*/%%'` + case " $oldobjs " in + " ") oldobjs=$obj ;; + *[\ /]"$objbase "*) + while :; do + # Make sure we don't pick an alternate name that also + # overlaps. + newobj=lt$counter-$objbase + counter=`expr $counter + 1` + case " $oldobjs " in + *[\ /]"$newobj "*) ;; + *) if test ! -f "$gentop/$newobj"; then break; fi ;; + esac + done + $show "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj" + $run ln "$obj" "$gentop/$newobj" || + $run cp "$obj" "$gentop/$newobj" + oldobjs="$oldobjs $gentop/$newobj" + ;; + *) oldobjs="$oldobjs $obj" ;; + esac + done + fi + + eval cmds=\"$old_archive_cmds\" + + if len=`expr "X$cmds" : ".*"` && + test "$len" -le "$max_cmd_len" || test "$max_cmd_len" -le -1; then + cmds=$old_archive_cmds + else + # the command line is too long to link in one step, link in parts + $echo "using piecewise archive linking..." + save_RANLIB=$RANLIB + RANLIB=: + objlist= + concat_cmds= + save_oldobjs=$oldobjs + + # Is there a better way of finding the last object in the list? + for obj in $save_oldobjs + do + last_oldobj=$obj + done + for obj in $save_oldobjs + do + oldobjs="$objlist $obj" + objlist="$objlist $obj" + eval test_cmds=\"$old_archive_cmds\" + if len=`expr "X$test_cmds" : ".*" 2>/dev/null` && + test "$len" -le "$max_cmd_len"; then + : + else + # the above command should be used before it gets too long + oldobjs=$objlist + if test "$obj" = "$last_oldobj" ; then + RANLIB=$save_RANLIB + fi + test -z "$concat_cmds" || concat_cmds=$concat_cmds~ + eval concat_cmds=\"\${concat_cmds}$old_archive_cmds\" + objlist= + fi + done + RANLIB=$save_RANLIB + oldobjs=$objlist + if test "X$oldobjs" = "X" ; then + eval cmds=\"\$concat_cmds\" + else + eval cmds=\"\$concat_cmds~\$old_archive_cmds\" + fi + fi + fi + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + eval cmd=\"$cmd\" + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + done + + if test -n "$generated"; then + $show "${rm}r$generated" + $run ${rm}r$generated + fi + + # Now create the libtool archive. + case $output in + *.la) + old_library= + test "$build_old_libs" = yes && old_library="$libname.$libext" + $show "creating $output" + + # Preserve any variables that may affect compiler behavior + for var in $variables_saved_for_relink; do + if eval test -z \"\${$var+set}\"; then + relink_command="{ test -z \"\${$var+set}\" || unset $var || { $var=; export $var; }; }; $relink_command" + elif eval var_value=\$$var; test -z "$var_value"; then + relink_command="$var=; export $var; $relink_command" + else + var_value=`$echo "X$var_value" | $Xsed -e "$sed_quote_subst"` + relink_command="$var=\"$var_value\"; export $var; $relink_command" + fi + done + # Quote the link command for shipping. + relink_command="(cd `pwd`; $SHELL $progpath $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)" + relink_command=`$echo "X$relink_command" | $SP2NL | $Xsed -e "$sed_quote_subst" | $NL2SP` + if test "$hardcode_automatic" = yes ; then + relink_command= + fi + + + # Only create the output if not a dry run. + if test -z "$run"; then + for installed in no yes; do + if test "$installed" = yes; then + if test -z "$install_libdir"; then + break + fi + output="$output_objdir/$outputname"i + # Replace all uninstalled libtool libraries with the installed ones + newdependency_libs= + for deplib in $dependency_libs; do + case $deplib in + *.la) + name=`$echo "X$deplib" | $Xsed -e 's%^.*/%%'` + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` + if test -z "$libdir"; then + $echo "$modename: \`$deplib' is not a valid libtool archive" 1>&2 + exit $EXIT_FAILURE + fi + newdependency_libs="$newdependency_libs $libdir/$name" + ;; + *) newdependency_libs="$newdependency_libs $deplib" ;; + esac + done + dependency_libs="$newdependency_libs" + newdlfiles= + for lib in $dlfiles; do + name=`$echo "X$lib" | $Xsed -e 's%^.*/%%'` + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` + if test -z "$libdir"; then + $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 + exit $EXIT_FAILURE + fi + newdlfiles="$newdlfiles $libdir/$name" + done + dlfiles="$newdlfiles" + newdlprefiles= + for lib in $dlprefiles; do + name=`$echo "X$lib" | $Xsed -e 's%^.*/%%'` + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` + if test -z "$libdir"; then + $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 + exit $EXIT_FAILURE + fi + newdlprefiles="$newdlprefiles $libdir/$name" + done + dlprefiles="$newdlprefiles" + else + newdlfiles= + for lib in $dlfiles; do + case $lib in + [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; + *) abs=`pwd`"/$lib" ;; + esac + newdlfiles="$newdlfiles $abs" + done + dlfiles="$newdlfiles" + newdlprefiles= + for lib in $dlprefiles; do + case $lib in + [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; + *) abs=`pwd`"/$lib" ;; + esac + newdlprefiles="$newdlprefiles $abs" + done + dlprefiles="$newdlprefiles" + fi + $rm $output + # place dlname in correct position for cygwin + tdlname=$dlname + case $host,$output,$installed,$module,$dlname in + *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll) tdlname=../bin/$dlname ;; + esac + $echo > $output "\ +# $outputname - a libtool library file +# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# The name that we can dlopen(3). +dlname='$tdlname' + +# Names of this library. +library_names='$library_names' + +# The name of the static archive. +old_library='$old_library' + +# Libraries that this one depends upon. +dependency_libs='$dependency_libs' + +# Version information for $libname. +current=$current +age=$age +revision=$revision + +# Is this an already installed library? +installed=$installed + +# Should we warn about portability when linking against -modules? +shouldnotlink=$module + +# Files to dlopen/dlpreopen +dlopen='$dlfiles' +dlpreopen='$dlprefiles' + +# Directory that this library needs to be installed in: +libdir='$install_libdir'" + if test "$installed" = no && test "$need_relink" = yes; then + $echo >> $output "\ +relink_command=\"$relink_command\"" + fi + done + fi + + # Do a symbolic link so that the libtool archive can be found in + # LD_LIBRARY_PATH before the program is installed. + $show "(cd $output_objdir && $rm $outputname && $LN_S ../$outputname $outputname)" + $run eval '(cd $output_objdir && $rm $outputname && $LN_S ../$outputname $outputname)' || exit $? + ;; + esac + exit $EXIT_SUCCESS + ;; + + # libtool install mode + install) + modename="$modename: install" + + # There may be an optional sh(1) argument at the beginning of + # install_prog (especially on Windows NT). + if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh || + # Allow the use of GNU shtool's install command. + $echo "X$nonopt" | grep shtool > /dev/null; then + # Aesthetically quote it. + arg=`$echo "X$nonopt" | $Xsed -e "$sed_quote_subst"` + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + install_prog="$arg " + arg="$1" + shift + else + install_prog= + arg=$nonopt + fi + + # The real first argument should be the name of the installation program. + # Aesthetically quote it. + arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + install_prog="$install_prog$arg" + + # We need to accept at least all the BSD install flags. + dest= + files= + opts= + prev= + install_type= + isdir=no + stripme= + for arg + do + if test -n "$dest"; then + files="$files $dest" + dest=$arg + continue + fi + + case $arg in + -d) isdir=yes ;; + -f) + case " $install_prog " in + *[\\\ /]cp\ *) ;; + *) prev=$arg ;; + esac + ;; + -g | -m | -o) prev=$arg ;; + -s) + stripme=" -s" + continue + ;; + -*) + ;; + *) + # If the previous option needed an argument, then skip it. + if test -n "$prev"; then + prev= + else + dest=$arg + continue + fi + ;; + esac + + # Aesthetically quote the argument. + arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + install_prog="$install_prog $arg" + done + + if test -z "$install_prog"; then + $echo "$modename: you must specify an install program" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + if test -n "$prev"; then + $echo "$modename: the \`$prev' option requires an argument" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + if test -z "$files"; then + if test -z "$dest"; then + $echo "$modename: no file or destination specified" 1>&2 + else + $echo "$modename: you must specify a destination" 1>&2 + fi + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + # Strip any trailing slash from the destination. + dest=`$echo "X$dest" | $Xsed -e 's%/$%%'` + + # Check to see that the destination is a directory. + test -d "$dest" && isdir=yes + if test "$isdir" = yes; then + destdir="$dest" + destname= + else + destdir=`$echo "X$dest" | $Xsed -e 's%/[^/]*$%%'` + test "X$destdir" = "X$dest" && destdir=. + destname=`$echo "X$dest" | $Xsed -e 's%^.*/%%'` + + # Not a directory, so check to see that there is only one file specified. + set dummy $files + if test "$#" -gt 2; then + $echo "$modename: \`$dest' is not a directory" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + fi + case $destdir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + for file in $files; do + case $file in + *.lo) ;; + *) + $echo "$modename: \`$destdir' must be an absolute directory name" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + ;; + esac + done + ;; + esac + + # This variable tells wrapper scripts just to set variables rather + # than running their programs. + libtool_install_magic="$magic" + + staticlibs= + future_libdirs= + current_libdirs= + for file in $files; do + + # Do each installation. + case $file in + *.$libext) + # Do the static libraries later. + staticlibs="$staticlibs $file" + ;; + + *.la) + # Check to see that this really is a libtool archive. + if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then : + else + $echo "$modename: \`$file' is not a valid libtool archive" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + library_names= + old_library= + relink_command= + # If there is no directory component, then add one. + case $file in + */* | *\\*) . $file ;; + *) . ./$file ;; + esac + + # Add the libdir to current_libdirs if it is the destination. + if test "X$destdir" = "X$libdir"; then + case "$current_libdirs " in + *" $libdir "*) ;; + *) current_libdirs="$current_libdirs $libdir" ;; + esac + else + # Note the libdir as a future libdir. + case "$future_libdirs " in + *" $libdir "*) ;; + *) future_libdirs="$future_libdirs $libdir" ;; + esac + fi + + dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`/ + test "X$dir" = "X$file/" && dir= + dir="$dir$objdir" + + if test -n "$relink_command"; then + # Determine the prefix the user has applied to our future dir. + inst_prefix_dir=`$echo "$destdir" | $SED "s%$libdir\$%%"` + + # Don't allow the user to place us outside of our expected + # location b/c this prevents finding dependent libraries that + # are installed to the same prefix. + # At present, this check doesn't affect windows .dll's that + # are installed into $libdir/../bin (currently, that works fine) + # but it's something to keep an eye on. + if test "$inst_prefix_dir" = "$destdir"; then + $echo "$modename: error: cannot install \`$file' to a directory not ending in $libdir" 1>&2 + exit $EXIT_FAILURE + fi + + if test -n "$inst_prefix_dir"; then + # Stick the inst_prefix_dir data into the link command. + relink_command=`$echo "$relink_command" | $SP2NL | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%" | $NL2SP` + else + relink_command=`$echo "$relink_command" | $SP2NL | $SED "s%@inst_prefix_dir@%%" | $NL2SP` + fi + + $echo "$modename: warning: relinking \`$file'" 1>&2 + $show "$relink_command" + if $run eval "$relink_command"; then : + else + $echo "$modename: error: relink \`$file' with the above command before installing it" 1>&2 + exit $EXIT_FAILURE + fi + fi + + # See the names of the shared library. + set dummy $library_names + if test -n "$2"; then + realname="$2" + shift + shift + + srcname="$realname" + test -n "$relink_command" && srcname="$realname"T + + # Install the shared library and build the symlinks. + $show "$install_prog $dir/$srcname $destdir/$realname" + $run eval "$install_prog $dir/$srcname $destdir/$realname" || exit $? + if test -n "$stripme" && test -n "$striplib"; then + $show "$striplib $destdir/$realname" + $run eval "$striplib $destdir/$realname" || exit $? + fi + + if test "$#" -gt 0; then + # Delete the old symlinks, and create new ones. + # Try `ln -sf' first, because the `ln' binary might depend on + # the symlink we replace! Solaris /bin/ln does not understand -f, + # so we also need to try rm && ln -s. + for linkname + do + if test "$linkname" != "$realname"; then + $show "(cd $destdir && { $LN_S -f $realname $linkname || { $rm $linkname && $LN_S $realname $linkname; }; })" + $run eval "(cd $destdir && { $LN_S -f $realname $linkname || { $rm $linkname && $LN_S $realname $linkname; }; })" + fi + done + fi + + # Do each command in the postinstall commands. + lib="$destdir/$realname" + cmds=$postinstall_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" || { + lt_exit=$? + + # Restore the uninstalled library and exit + if test "$mode" = relink; then + $run eval '(cd $output_objdir && $rm ${realname}T && $mv ${realname}U $realname)' + fi + + exit $lt_exit + } + done + IFS="$save_ifs" + fi + + # Install the pseudo-library for information purposes. + name=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + instname="$dir/$name"i + $show "$install_prog $instname $destdir/$name" + $run eval "$install_prog $instname $destdir/$name" || exit $? + + # Maybe install the static library, too. + test -n "$old_library" && staticlibs="$staticlibs $dir/$old_library" + ;; + + *.lo) + # Install (i.e. copy) a libtool object. + + # Figure out destination file name, if it wasn't already specified. + if test -n "$destname"; then + destfile="$destdir/$destname" + else + destfile=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + destfile="$destdir/$destfile" + fi + + # Deduce the name of the destination old-style object file. + case $destfile in + *.lo) + staticdest=`$echo "X$destfile" | $Xsed -e "$lo2o"` + ;; + *.$objext) + staticdest="$destfile" + destfile= + ;; + *) + $echo "$modename: cannot copy a libtool object to \`$destfile'" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + ;; + esac + + # Install the libtool object if requested. + if test -n "$destfile"; then + $show "$install_prog $file $destfile" + $run eval "$install_prog $file $destfile" || exit $? + fi + + # Install the old object if enabled. + if test "$build_old_libs" = yes; then + # Deduce the name of the old-style object file. + staticobj=`$echo "X$file" | $Xsed -e "$lo2o"` + + $show "$install_prog $staticobj $staticdest" + $run eval "$install_prog \$staticobj \$staticdest" || exit $? + fi + exit $EXIT_SUCCESS + ;; + + *) + # Figure out destination file name, if it wasn't already specified. + if test -n "$destname"; then + destfile="$destdir/$destname" + else + destfile=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + destfile="$destdir/$destfile" + fi + + # If the file is missing, and there is a .exe on the end, strip it + # because it is most likely a libtool script we actually want to + # install + stripped_ext="" + case $file in + *.exe) + if test ! -f "$file"; then + file=`$echo $file|${SED} 's,.exe$,,'` + stripped_ext=".exe" + fi + ;; + esac + + # Do a test to see if this is really a libtool program. + case $host in + *cygwin*|*mingw*) + wrapper=`$echo $file | ${SED} -e 's,.exe$,,'` + ;; + *) + wrapper=$file + ;; + esac + if (${SED} -e '4q' $wrapper | grep "^# Generated by .*$PACKAGE")>/dev/null 2>&1; then + notinst_deplibs= + relink_command= + + # Note that it is not necessary on cygwin/mingw to append a dot to + # foo even if both foo and FILE.exe exist: automatic-append-.exe + # behavior happens only for exec(3), not for open(2)! Also, sourcing + # `FILE.' does not work on cygwin managed mounts. + # + # If there is no directory component, then add one. + case $wrapper in + */* | *\\*) . ${wrapper} ;; + *) . ./${wrapper} ;; + esac + + # Check the variables that should have been set. + if test -z "$notinst_deplibs"; then + $echo "$modename: invalid libtool wrapper script \`$wrapper'" 1>&2 + exit $EXIT_FAILURE + fi + + finalize=yes + for lib in $notinst_deplibs; do + # Check to see that each library is installed. + libdir= + if test -f "$lib"; then + # If there is no directory component, then add one. + case $lib in + */* | *\\*) . $lib ;; + *) . ./$lib ;; + esac + fi + libfile="$libdir/"`$echo "X$lib" | $Xsed -e 's%^.*/%%g'` ### testsuite: skip nested quoting test + if test -n "$libdir" && test ! -f "$libfile"; then + $echo "$modename: warning: \`$lib' has not been installed in \`$libdir'" 1>&2 + finalize=no + fi + done + + relink_command= + # Note that it is not necessary on cygwin/mingw to append a dot to + # foo even if both foo and FILE.exe exist: automatic-append-.exe + # behavior happens only for exec(3), not for open(2)! Also, sourcing + # `FILE.' does not work on cygwin managed mounts. + # + # If there is no directory component, then add one. + case $wrapper in + */* | *\\*) . ${wrapper} ;; + *) . ./${wrapper} ;; + esac + + outputname= + if test "$fast_install" = no && test -n "$relink_command"; then + if test "$finalize" = yes && test -z "$run"; then + tmpdir=`func_mktempdir` + file=`$echo "X$file$stripped_ext" | $Xsed -e 's%^.*/%%'` + outputname="$tmpdir/$file" + # Replace the output file specification. + relink_command=`$echo "X$relink_command" | $SP2NL | $Xsed -e 's%@OUTPUT@%'"$outputname"'%g' | $NL2SP` + + $show "$relink_command" + if $run eval "$relink_command"; then : + else + $echo "$modename: error: relink \`$file' with the above command before installing it" 1>&2 + ${rm}r "$tmpdir" + continue + fi + file="$outputname" + else + $echo "$modename: warning: cannot relink \`$file'" 1>&2 + fi + else + # Install the binary that we compiled earlier. + file=`$echo "X$file$stripped_ext" | $Xsed -e "s%\([^/]*\)$%$objdir/\1%"` + fi + fi + + # remove .exe since cygwin /usr/bin/install will append another + # one anyway + case $install_prog,$host in + */usr/bin/install*,*cygwin*) + case $file:$destfile in + *.exe:*.exe) + # this is ok + ;; + *.exe:*) + destfile=$destfile.exe + ;; + *:*.exe) + destfile=`$echo $destfile | ${SED} -e 's,.exe$,,'` + ;; + esac + ;; + esac + $show "$install_prog$stripme $file $destfile" + $run eval "$install_prog\$stripme \$file \$destfile" || exit $? + test -n "$outputname" && ${rm}r "$tmpdir" + ;; + esac + done + + for file in $staticlibs; do + name=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + + # Set up the ranlib parameters. + oldlib="$destdir/$name" + + $show "$install_prog $file $oldlib" + $run eval "$install_prog \$file \$oldlib" || exit $? + + if test -n "$stripme" && test -n "$old_striplib"; then + $show "$old_striplib $oldlib" + $run eval "$old_striplib $oldlib" || exit $? + fi + + # Do each command in the postinstall commands. + cmds=$old_postinstall_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + done + + if test -n "$future_libdirs"; then + $echo "$modename: warning: remember to run \`$progname --finish$future_libdirs'" 1>&2 + fi + + if test -n "$current_libdirs"; then + # Maybe just do a dry run. + test -n "$run" && current_libdirs=" -n$current_libdirs" + exec_cmd='$SHELL $progpath $preserve_args --finish$current_libdirs' + else + exit $EXIT_SUCCESS + fi + ;; + + # libtool finish mode + finish) + modename="$modename: finish" + libdirs="$nonopt" + admincmds= + + if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then + for dir + do + libdirs="$libdirs $dir" + done + + for libdir in $libdirs; do + if test -n "$finish_cmds"; then + # Do each command in the finish commands. + cmds=$finish_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" || admincmds="$admincmds + $cmd" + done + IFS="$save_ifs" + fi + if test -n "$finish_eval"; then + # Do the single finish_eval. + eval cmds=\"$finish_eval\" + $run eval "$cmds" || admincmds="$admincmds + $cmds" + fi + done + fi + + # Exit here if they wanted silent mode. + test "$show" = : && exit $EXIT_SUCCESS + + $echo "X----------------------------------------------------------------------" | $Xsed + $echo "Libraries have been installed in:" + for libdir in $libdirs; do + $echo " $libdir" + done + $echo + $echo "If you ever happen to want to link against installed libraries" + $echo "in a given directory, LIBDIR, you must either use libtool, and" + $echo "specify the full pathname of the library, or use the \`-LLIBDIR'" + $echo "flag during linking and do at least one of the following:" + if test -n "$shlibpath_var"; then + $echo " - add LIBDIR to the \`$shlibpath_var' environment variable" + $echo " during execution" + fi + if test -n "$runpath_var"; then + $echo " - add LIBDIR to the \`$runpath_var' environment variable" + $echo " during linking" + fi + if test -n "$hardcode_libdir_flag_spec"; then + libdir=LIBDIR + eval flag=\"$hardcode_libdir_flag_spec\" + + $echo " - use the \`$flag' linker flag" + fi + if test -n "$admincmds"; then + $echo " - have your system administrator run these commands:$admincmds" + fi + if test -f /etc/ld.so.conf; then + $echo " - have your system administrator add LIBDIR to \`/etc/ld.so.conf'" + fi + $echo + $echo "See any operating system documentation about shared libraries for" + $echo "more information, such as the ld(1) and ld.so(8) manual pages." + $echo "X----------------------------------------------------------------------" | $Xsed + exit $EXIT_SUCCESS + ;; + + # libtool execute mode + execute) + modename="$modename: execute" + + # The first argument is the command name. + cmd="$nonopt" + if test -z "$cmd"; then + $echo "$modename: you must specify a COMMAND" 1>&2 + $echo "$help" + exit $EXIT_FAILURE + fi + + # Handle -dlopen flags immediately. + for file in $execute_dlfiles; do + if test ! -f "$file"; then + $echo "$modename: \`$file' is not a file" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + dir= + case $file in + *.la) + # Check to see that this really is a libtool archive. + if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then : + else + $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + # Read the libtool library. + dlname= + library_names= + + # If there is no directory component, then add one. + case $file in + */* | *\\*) . $file ;; + *) . ./$file ;; + esac + + # Skip this library if it cannot be dlopened. + if test -z "$dlname"; then + # Warn if it was a shared library. + test -n "$library_names" && $echo "$modename: warning: \`$file' was not linked with \`-export-dynamic'" + continue + fi + + dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'` + test "X$dir" = "X$file" && dir=. + + if test -f "$dir/$objdir/$dlname"; then + dir="$dir/$objdir" + else + if test ! -f "$dir/$dlname"; then + $echo "$modename: cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'" 1>&2 + exit $EXIT_FAILURE + fi + fi + ;; + + *.lo) + # Just add the directory containing the .lo file. + dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'` + test "X$dir" = "X$file" && dir=. + ;; + + *) + $echo "$modename: warning \`-dlopen' is ignored for non-libtool libraries and objects" 1>&2 + continue + ;; + esac + + # Get the absolute pathname. + absdir=`cd "$dir" && pwd` + test -n "$absdir" && dir="$absdir" + + # Now add the directory to shlibpath_var. + if eval "test -z \"\$$shlibpath_var\""; then + eval "$shlibpath_var=\"\$dir\"" + else + eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\"" + fi + done + + # This variable tells wrapper scripts just to set shlibpath_var + # rather than running their programs. + libtool_execute_magic="$magic" + + # Check if any of the arguments is a wrapper script. + args= + for file + do + case $file in + -*) ;; + *) + # Do a test to see if this is really a libtool program. + if (${SED} -e '4q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + # If there is no directory component, then add one. + case $file in + */* | *\\*) . $file ;; + *) . ./$file ;; + esac + + # Transform arg to wrapped name. + file="$progdir/$program" + fi + ;; + esac + # Quote arguments (to preserve shell metacharacters). + file=`$echo "X$file" | $Xsed -e "$sed_quote_subst"` + args="$args \"$file\"" + done + + if test -z "$run"; then + if test -n "$shlibpath_var"; then + # Export the shlibpath_var. + eval "export $shlibpath_var" + fi + + # Restore saved environment variables + for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES + do + eval "if test \"\${save_$lt_var+set}\" = set; then + $lt_var=\$save_$lt_var; export $lt_var + fi" + done + + # Now prepare to actually exec the command. + exec_cmd="\$cmd$args" + else + # Display what would be done. + if test -n "$shlibpath_var"; then + eval "\$echo \"\$shlibpath_var=\$$shlibpath_var\"" + $echo "export $shlibpath_var" + fi + $echo "$cmd$args" + exit $EXIT_SUCCESS + fi + ;; + + # libtool clean and uninstall mode + clean | uninstall) + modename="$modename: $mode" + rm="$nonopt" + files= + rmforce= + exit_status=0 + + # This variable tells wrapper scripts just to set variables rather + # than running their programs. + libtool_install_magic="$magic" + + for arg + do + case $arg in + -f) rm="$rm $arg"; rmforce=yes ;; + -*) rm="$rm $arg" ;; + *) files="$files $arg" ;; + esac + done + + if test -z "$rm"; then + $echo "$modename: you must specify an RM program" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + rmdirs= + + origobjdir="$objdir" + for file in $files; do + dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'` + if test "X$dir" = "X$file"; then + dir=. + objdir="$origobjdir" + else + objdir="$dir/$origobjdir" + fi + name=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + test "$mode" = uninstall && objdir="$dir" + + # Remember objdir for removal later, being careful to avoid duplicates + if test "$mode" = clean; then + case " $rmdirs " in + *" $objdir "*) ;; + *) rmdirs="$rmdirs $objdir" ;; + esac + fi + + # Don't error if the file doesn't exist and rm -f was used. + if (test -L "$file") >/dev/null 2>&1 \ + || (test -h "$file") >/dev/null 2>&1 \ + || test -f "$file"; then + : + elif test -d "$file"; then + exit_status=1 + continue + elif test "$rmforce" = yes; then + continue + fi + + rmfiles="$file" + + case $name in + *.la) + # Possibly a libtool archive, so verify it. + if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + . $dir/$name + + # Delete the libtool libraries and symlinks. + for n in $library_names; do + rmfiles="$rmfiles $objdir/$n" + done + test -n "$old_library" && rmfiles="$rmfiles $objdir/$old_library" + + case "$mode" in + clean) + case " $library_names " in + # " " in the beginning catches empty $dlname + *" $dlname "*) ;; + *) rmfiles="$rmfiles $objdir/$dlname" ;; + esac + test -n "$libdir" && rmfiles="$rmfiles $objdir/$name $objdir/${name}i" + ;; + uninstall) + if test -n "$library_names"; then + # Do each command in the postuninstall commands. + cmds=$postuninstall_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" + if test "$?" -ne 0 && test "$rmforce" != yes; then + exit_status=1 + fi + done + IFS="$save_ifs" + fi + + if test -n "$old_library"; then + # Do each command in the old_postuninstall commands. + cmds=$old_postuninstall_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" + if test "$?" -ne 0 && test "$rmforce" != yes; then + exit_status=1 + fi + done + IFS="$save_ifs" + fi + # FIXME: should reinstall the best remaining shared library. + ;; + esac + fi + ;; + + *.lo) + # Possibly a libtool object, so verify it. + if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + + # Read the .lo file + . $dir/$name + + # Add PIC object to the list of files to remove. + if test -n "$pic_object" \ + && test "$pic_object" != none; then + rmfiles="$rmfiles $dir/$pic_object" + fi + + # Add non-PIC object to the list of files to remove. + if test -n "$non_pic_object" \ + && test "$non_pic_object" != none; then + rmfiles="$rmfiles $dir/$non_pic_object" + fi + fi + ;; + + *) + if test "$mode" = clean ; then + noexename=$name + case $file in + *.exe) + file=`$echo $file|${SED} 's,.exe$,,'` + noexename=`$echo $name|${SED} 's,.exe$,,'` + # $file with .exe has already been added to rmfiles, + # add $file without .exe + rmfiles="$rmfiles $file" + ;; + esac + # Do a test to see if this is a libtool program. + if (${SED} -e '4q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + relink_command= + . $dir/$noexename + + # note $name still contains .exe if it was in $file originally + # as does the version of $file that was added into $rmfiles + rmfiles="$rmfiles $objdir/$name $objdir/${name}S.${objext}" + if test "$fast_install" = yes && test -n "$relink_command"; then + rmfiles="$rmfiles $objdir/lt-$name" + fi + if test "X$noexename" != "X$name" ; then + rmfiles="$rmfiles $objdir/lt-${noexename}.c" + fi + fi + fi + ;; + esac + $show "$rm $rmfiles" + $run $rm $rmfiles || exit_status=1 + done + objdir="$origobjdir" + + # Try to remove the ${objdir}s in the directories where we deleted files + for dir in $rmdirs; do + if test -d "$dir"; then + $show "rmdir $dir" + $run rmdir $dir >/dev/null 2>&1 + fi + done + + exit $exit_status + ;; + + "") + $echo "$modename: you must specify a MODE" 1>&2 + $echo "$generic_help" 1>&2 + exit $EXIT_FAILURE + ;; + esac + + if test -z "$exec_cmd"; then + $echo "$modename: invalid operation mode \`$mode'" 1>&2 + $echo "$generic_help" 1>&2 + exit $EXIT_FAILURE + fi +fi # test -z "$show_help" + +if test -n "$exec_cmd"; then + eval exec $exec_cmd + exit $EXIT_FAILURE +fi + +# We need to display help for each of the modes. +case $mode in +"") $echo \ +"Usage: $modename [OPTION]... [MODE-ARG]... + +Provide generalized library-building support services. + + --config show all configuration variables + --debug enable verbose shell tracing +-n, --dry-run display commands without modifying any files + --features display basic configuration information and exit + --finish same as \`--mode=finish' + --help display this help message and exit + --mode=MODE use operation mode MODE [default=inferred from MODE-ARGS] + --quiet same as \`--silent' + --silent don't print informational messages + --tag=TAG use configuration variables from tag TAG + --version print version information + +MODE must be one of the following: + + clean remove files from the build directory + compile compile a source file into a libtool object + execute automatically set library path, then run a program + finish complete the installation of libtool libraries + install install libraries or executables + link create a library or an executable + uninstall remove libraries from an installed directory + +MODE-ARGS vary depending on the MODE. Try \`$modename --help --mode=MODE' for +a more detailed description of MODE. + +Report bugs to ." + exit $EXIT_SUCCESS + ;; + +clean) + $echo \ +"Usage: $modename [OPTION]... --mode=clean RM [RM-OPTION]... FILE... + +Remove files from the build directory. + +RM is the name of the program to use to delete files associated with each FILE +(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed +to RM. + +If FILE is a libtool library, object or program, all the files associated +with it are deleted. Otherwise, only FILE itself is deleted using RM." + ;; + +compile) + $echo \ +"Usage: $modename [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE + +Compile a source file into a libtool library object. + +This mode accepts the following additional options: + + -o OUTPUT-FILE set the output file name to OUTPUT-FILE + -prefer-pic try to building PIC objects only + -prefer-non-pic try to building non-PIC objects only + -static always build a \`.o' file suitable for static linking + +COMPILE-COMMAND is a command to be used in creating a \`standard' object file +from the given SOURCEFILE. + +The output file name is determined by removing the directory component from +SOURCEFILE, then substituting the C source code suffix \`.c' with the +library object suffix, \`.lo'." + ;; + +execute) + $echo \ +"Usage: $modename [OPTION]... --mode=execute COMMAND [ARGS]... + +Automatically set library path, then run a program. + +This mode accepts the following additional options: + + -dlopen FILE add the directory containing FILE to the library path + +This mode sets the library path environment variable according to \`-dlopen' +flags. + +If any of the ARGS are libtool executable wrappers, then they are translated +into their corresponding uninstalled binary, and any of their required library +directories are added to the library path. + +Then, COMMAND is executed, with ARGS as arguments." + ;; + +finish) + $echo \ +"Usage: $modename [OPTION]... --mode=finish [LIBDIR]... + +Complete the installation of libtool libraries. + +Each LIBDIR is a directory that contains libtool libraries. + +The commands that this mode executes may require superuser privileges. Use +the \`--dry-run' option if you just want to see what would be executed." + ;; + +install) + $echo \ +"Usage: $modename [OPTION]... --mode=install INSTALL-COMMAND... + +Install executables or libraries. + +INSTALL-COMMAND is the installation command. The first component should be +either the \`install' or \`cp' program. + +The rest of the components are interpreted as arguments to that command (only +BSD-compatible install options are recognized)." + ;; + +link) + $echo \ +"Usage: $modename [OPTION]... --mode=link LINK-COMMAND... + +Link object files or libraries together to form another library, or to +create an executable program. + +LINK-COMMAND is a command using the C compiler that you would use to create +a program from several object files. + +The following components of LINK-COMMAND are treated specially: + + -all-static do not do any dynamic linking at all + -avoid-version do not add a version suffix if possible + -dlopen FILE \`-dlpreopen' FILE if it cannot be dlopened at runtime + -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols + -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3) + -export-symbols SYMFILE + try to export only the symbols listed in SYMFILE + -export-symbols-regex REGEX + try to export only the symbols matching REGEX + -LLIBDIR search LIBDIR for required installed libraries + -lNAME OUTPUT-FILE requires the installed library libNAME + -module build a library that can dlopened + -no-fast-install disable the fast-install mode + -no-install link a not-installable executable + -no-undefined declare that a library does not refer to external symbols + -o OUTPUT-FILE create OUTPUT-FILE from the specified objects + -objectlist FILE Use a list of object files found in FILE to specify objects + -precious-files-regex REGEX + don't remove output files matching REGEX + -release RELEASE specify package release information + -rpath LIBDIR the created library will eventually be installed in LIBDIR + -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries + -static do not do any dynamic linking of uninstalled libtool libraries + -static-libtool-libs + do not do any dynamic linking of libtool libraries + -version-info CURRENT[:REVISION[:AGE]] + specify library version info [each variable defaults to 0] + +All other options (arguments beginning with \`-') are ignored. + +Every other argument is treated as a filename. Files ending in \`.la' are +treated as uninstalled libtool libraries, other files are standard or library +object files. + +If the OUTPUT-FILE ends in \`.la', then a libtool library is created, +only library objects (\`.lo' files) may be specified, and \`-rpath' is +required, except when creating a convenience library. + +If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created +using \`ar' and \`ranlib', or on Windows using \`lib'. + +If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file +is created, otherwise an executable program is created." + ;; + +uninstall) + $echo \ +"Usage: $modename [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE... + +Remove libraries from an installation directory. + +RM is the name of the program to use to delete files associated with each FILE +(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed +to RM. + +If FILE is a libtool library, all the files associated with it are deleted. +Otherwise, only FILE itself is deleted using RM." + ;; + +*) + $echo "$modename: invalid operation mode \`$mode'" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + ;; +esac + +$echo +$echo "Try \`$modename --help' for more information about other modes." + +exit $? + +# The TAGs below are defined such that we never get into a situation +# in which we disable both kinds of libraries. Given conflicting +# choices, we go for a static library, that is the most portable, +# since we can't tell whether shared libraries were disabled because +# the user asked for that or because the platform doesn't support +# them. This is particularly important on AIX, because we don't +# support having both static and shared libraries enabled at the same +# time on that platform, so we default to a shared-only configuration. +# If a disable-shared tag is given, we'll fallback to a static-only +# configuration. But we'll never go from static-only to shared-only. + +# ### BEGIN LIBTOOL TAG CONFIG: disable-shared +disable_libs=shared +# ### END LIBTOOL TAG CONFIG: disable-shared + +# ### BEGIN LIBTOOL TAG CONFIG: disable-static +disable_libs=static +# ### END LIBTOOL TAG CONFIG: disable-static + +# Local Variables: +# mode:shell-script +# sh-indentation:2 +# End: +# ### BEGIN LIBTOOL TAG CONFIG: CXX + +# Libtool was configured on host announce: + +# Shell to use when invoking shell scripts. +SHELL="/bin/bash" + +# Whether or not to build shared libraries. +build_libtool_libs=yes + +# Whether or not to build static libraries. +build_old_libs=yes + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=no + +# Whether or not to disallow shared libs when runtime libs are static +allow_libtool_libs_with_static_runtimes=no + +# Whether or not to optimize for fast installation. +fast_install=yes + +# The host system. +host_alias=arc-linux-uclibc +host=arc-unknown-linux-uclibc +host_os=linux-uclibc + +# The build system. +build_alias= +build=i686-pc-linux-gnu +build_os=linux-gnu + +# An echo program that does not interpret backslashes. +echo="echo" + +# The archiver. +AR="arc-linux-uclibc-ar" +AR_FLAGS="cru" + +# A C compiler. +LTCC="arc-linux-uclibc-gcc" + +# LTCC compiler flags. +LTCFLAGS="-mA7 -g" + +# A language-specific compiler. +CC="arc-linux-uclibc-g++" + +# Is the compiler the GNU C compiler? +with_gcc=yes + +# An ERE matcher. +EGREP="/bin/grep -E" + +# The linker used to build libraries. +LD="/opt/gnutools/arc2.3-p0/uclibc-4.2.1/arc-linux-uclibc/bin/ld" + +# Whether we need hard or soft links. +LN_S="ln -s" + +# A BSD-compatible nm program. +NM="/opt/gnutools/arc2.3-p0/uclibc-4.2.1/bin/arc-linux-uclibc-nm -B" + +# A symbol stripping program +STRIP="arc-linux-uclibc-strip" + +# Used to examine libraries when file_magic_cmd begins "file" +MAGIC_CMD=file + +# Used on cygwin: DLL creation program. +DLLTOOL="dlltool" + +# Used on cygwin: object dumper. +OBJDUMP="objdump" + +# Used on cygwin: assembler. +AS="as" + +# The name of the directory that contains temporary libtool files. +objdir=.libs + +# How to create reloadable object files. +reload_flag=" -r" +reload_cmds="\$LD\$reload_flag -o \$output\$reload_objs" + +# How to pass a linker flag through the compiler. +wl="-Wl," + +# Object file suffix (normally "o"). +objext="o" + +# Old archive suffix (normally "a"). +libext="a" + +# Shared library suffix (normally ".so"). +shrext_cmds='.so' + +# Executable file suffix (normally ""). +exeext="" + +# Additional compiler flags for building library objects. +pic_flag=" -fPIC -DPIC" +pic_mode=default + +# What is the maximum length of a command? +max_cmd_len=805306365 + +# Does compiler simultaneously support -c and -o options? +compiler_c_o="yes" + +# Must we lock files when doing compilation? +need_locks="no" + +# Do we need the lib prefix for modules? +need_lib_prefix=no + +# Do we need a version for libraries? +need_version=no + +# Whether dlopen is supported. +dlopen_support=unknown + +# Whether dlopen of programs is supported. +dlopen_self=unknown + +# Whether dlopen of statically linked programs is supported. +dlopen_self_static=unknown + +# Compiler flag to prevent dynamic linking. +link_static_flag="-static" + +# Compiler flag to turn off builtin functions. +no_builtin_flag=" -fno-builtin" + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec="\${wl}--export-dynamic" + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec="\${wl}--whole-archive\$convenience \${wl}--no-whole-archive" + +# Compiler flag to generate thread-safe objects. +thread_safe_flag_spec="" + +# Library versioning type. +version_type=linux + +# Format of library name prefix. +libname_spec="lib\$name" + +# List of archive names. First name is the real one, the rest are links. +# The last name is the one that the linker finds with -lNAME. +library_names_spec="\${libname}\${release}\${shared_ext}\$versuffix \${libname}\${release}\${shared_ext}\$major \$libname\${shared_ext}" + +# The coded name of the library, if different from the real name. +soname_spec="\${libname}\${release}\${shared_ext}\$major" + +# Commands used to build and install an old-style archive. +RANLIB="arc-linux-uclibc-ranlib" +old_archive_cmds="\$AR \$AR_FLAGS \$oldlib\$oldobjs~\$RANLIB \$oldlib" +old_postinstall_cmds="chmod 644 \$oldlib~\$RANLIB \$oldlib" +old_postuninstall_cmds="" + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds="" + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds="" + +# Commands used to build and install a shared archive. +archive_cmds="\$CC -shared -nostdlib \$predep_objects \$libobjs \$deplibs \$postdep_objects \$compiler_flags \${wl}-soname \$wl\$soname -o \$lib" +archive_expsym_cmds="\$CC -shared -nostdlib \$predep_objects \$libobjs \$deplibs \$postdep_objects \$compiler_flags \${wl}-soname \$wl\$soname \${wl}-retain-symbols-file \$wl\$export_symbols -o \$lib" +postinstall_cmds="" +postuninstall_cmds="" + +# Commands used to build a loadable module (assumed same as above if empty) +module_cmds="" +module_expsym_cmds="" + +# Commands to strip libraries. +old_striplib="arc-linux-uclibc-strip --strip-debug" +striplib="arc-linux-uclibc-strip --strip-unneeded" + +# Dependencies to place before the objects being linked to create a +# shared library. +predep_objects="/opt/gnutools/arc2.3-p0/uclibc-4.2.1/lib/gcc/arc-linux-uclibc/4.2.1/crti.o /opt/gnutools/arc2.3-p0/uclibc-4.2.1/lib/gcc/arc-linux-uclibc/4.2.1/crtbeginS.o" + +# Dependencies to place after the objects being linked to create a +# shared library. +postdep_objects="/opt/gnutools/arc2.3-p0/uclibc-4.2.1/lib/gcc/arc-linux-uclibc/4.2.1/crtendS.o /opt/gnutools/arc2.3-p0/uclibc-4.2.1/lib/gcc/arc-linux-uclibc/4.2.1/crtn.o" + +# Dependencies to place before the objects being linked to create a +# shared library. +predeps="" + +# Dependencies to place after the objects being linked to create a +# shared library. +postdeps="-lstdc++ -lm -lgcc_s -lc -lgcc_s" + +# The directories searched by this compiler when creating a shared +# library +compiler_lib_search_dirs="/opt/gnutools/arc2.3-p0/uclibc-4.2.1/lib/gcc/arc-linux-uclibc/4.2.1 /opt/gnutools/arc2.3-p0/uclibc-4.2.1/lib/gcc/arc-linux-uclibc/4.2.1/../../../../arc-linux-uclibc/lib" + +# The library search path used internally by the compiler when linking +# a shared library. +compiler_lib_search_path="-L/opt/gnutools/arc2.3-p0/uclibc-4.2.1/lib/gcc/arc-linux-uclibc/4.2.1 -L/opt/gnutools/arc2.3-p0/uclibc-4.2.1/lib/gcc/arc-linux-uclibc/4.2.1/../../../../arc-linux-uclibc/lib" + +# Method to check whether dependent libraries are shared objects. +deplibs_check_method="pass_all" + +# Command to use when deplibs_check_method == file_magic. +file_magic_cmd="\$MAGIC_CMD" + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag="" + +# Flag that forces no undefined symbols. +no_undefined_flag="" + +# Commands used to finish a libtool library installation in a directory. +finish_cmds="PATH=\\\"\\\$PATH:/sbin\\\" ldconfig -n \$libdir" + +# Same as above, but a single script fragment to be evaled but not shown. +finish_eval="" + +# Take the output of nm and produce a listing of raw symbols and C names. +global_symbol_pipe="sed -n -e 's/^.*[ ]\\([ABCDGIRSTW][ABCDGIRSTW]*\\)[ ][ ]*\\([_A-Za-z][_A-Za-z0-9]*\\)\$/\\1 \\2 \\2/p'" + +# Transform the output of nm in a proper C declaration +global_symbol_to_cdecl="sed -n -e 's/^. .* \\(.*\\)\$/extern int \\1;/p'" + +# Transform the output of nm in a C name address pair +global_symbol_to_c_name_address="sed -n -e 's/^: \\([^ ]*\\) \$/ {\\\"\\1\\\", (lt_ptr) 0},/p' -e 's/^[BCDEGRST] \\([^ ]*\\) \\([^ ]*\\)\$/ {\"\\2\", (lt_ptr) \\&\\2},/p'" + +# This is the shared library runtime path variable. +runpath_var=LD_RUN_PATH + +# This is the shared library path variable. +shlibpath_var=LD_LIBRARY_PATH + +# Is shlibpath searched before the hard-coded library search path? +shlibpath_overrides_runpath=no + +# How to hardcode a shared library path into an executable. +hardcode_action=immediate + +# Whether we should hardcode library paths into libraries. +hardcode_into_libs=yes + +# Flag to hardcode $libdir into a binary during linking. +# This must work even if $libdir does not exist. +hardcode_libdir_flag_spec="\${wl}--rpath \${wl}\$libdir" + +# If ld is used when linking, flag to hardcode $libdir into +# a binary during linking. This must work even if $libdir does +# not exist. +hardcode_libdir_flag_spec_ld="" + +# Whether we need a single -rpath flag with a separated argument. +hardcode_libdir_separator="" + +# Set to yes if using DIR/libNAME during linking hardcodes DIR into the +# resulting binary. +hardcode_direct=no + +# Set to yes if using the -LDIR flag during linking hardcodes DIR into the +# resulting binary. +hardcode_minus_L=no + +# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into +# the resulting binary. +hardcode_shlibpath_var=unsupported + +# Set to yes if building a shared library automatically hardcodes DIR into the library +# and all subsequent libraries and executables linked against it. +hardcode_automatic=no + +# Variables whose values should be saved in libtool wrapper scripts and +# restored at relink time. +variables_saved_for_relink="PATH LD_LIBRARY_PATH LD_RUN_PATH GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=unknown + +# Compile-time system search path for libraries +sys_lib_search_path_spec="/opt/gnutools/arc2.3-p0/uclibc-4.2.1/lib/gcc/arc-linux-uclibc/4.2.1 /opt/gnutools/arc2.3-p0/uclibc-4.2.1/arc-linux-uclibc/lib" + +# Run-time system search path for libraries +sys_lib_dlsearch_path_spec="/lib /usr/lib /lib/i486-linux-gnu /usr/lib/i486-linux-gnu /usr/lib/alsa-lib /usr/local/lib " + +# Fix the shell variable $srcfile for the compiler. +fix_srcfile_path="" + +# Set to yes if exported symbols are required. +always_export_symbols=no + +# The commands to list exported symbols. +export_symbols_cmds="\$NM \$libobjs \$convenience | \$global_symbol_pipe | \$SED 's/.* //' | sort | uniq > \$export_symbols" + +# The commands to extract the exported symbol list from a shared archive. +extract_expsyms_cmds="" + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms="_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*" + +# Symbols that must always be exported. +include_expsyms="" + +# ### END LIBTOOL TAG CONFIG: CXX + diff --git a/ltmain.sh b/ltmain.sh new file mode 100755 index 0000000..27d498a --- a/dev/null +++ b/ltmain.sh @@ -0,0 +1,6956 @@ +# ltmain.sh - Provide generalized library-building support services. +# NOTE: Changing this file will not affect anything until you rerun configure. +# +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006, +# 2007, 2008 Free Software Foundation, Inc. +# Originally by Gordon Matzigkeit , 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 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# 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. + +basename="s,^.*/,,g" + +# Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh +# is ksh but when the shell is invoked as "sh" and the current value of +# the _XPG environment variable is not equal to 1 (one), the special +# positional parameter $0, within a function call, is the name of the +# function. +progpath="$0" + +# The name of this program: +progname=`echo "$progpath" | $SED $basename` +modename="$progname" + +# Global variables: +EXIT_SUCCESS=0 +EXIT_FAILURE=1 + +PROGRAM=ltmain.sh +PACKAGE=libtool +VERSION=1.5.26 +TIMESTAMP=" (1.1220.2.492 2008/01/30 06:40:56)" + +# Be Bourne compatible (taken from Autoconf:_AS_BOURNE_COMPATIBLE). +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs 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 +BIN_SH=xpg4; export BIN_SH # for Tru64 +DUALCASE=1; export DUALCASE # for MKS sh + +# Check that we have a working $echo. +if test "X$1" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift +elif test "X$1" = X--fallback-echo; then + # Avoid inline document here, it may be left over + : +elif test "X`($echo '\t') 2>/dev/null`" = 'X\t'; then + # Yippee, $echo works! + : +else + # Restart under the correct shell, and then maybe $echo will work. + exec $SHELL "$progpath" --no-reexec ${1+"$@"} +fi + +if test "X$1" = X--fallback-echo; then + # used as fallback echo + shift + cat <&2 + $echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2 + exit $EXIT_FAILURE +fi + +# Global variables. +mode=$default_mode +nonopt= +prev= +prevopt= +run= +show="$echo" +show_help= +execute_dlfiles= +duplicate_deps=no +preserve_args= +lo2o="s/\\.lo\$/.${objext}/" +o2lo="s/\\.${objext}\$/.lo/" +extracted_archives= +extracted_serial=0 + +##################################### +# Shell function definitions: +# This seems to be the best place for them + +# func_mktempdir [string] +# Make a temporary directory that won't clash with other running +# libtool processes, and avoids race conditions if possible. If +# given, STRING is the basename for that directory. +func_mktempdir () +{ + my_template="${TMPDIR-/tmp}/${1-$progname}" + + if test "$run" = ":"; then + # Return a directory name, but don't create it in dry-run mode + my_tmpdir="${my_template}-$$" + else + + # If mktemp works, use that first and foremost + my_tmpdir=`mktemp -d "${my_template}-XXXXXXXX" 2>/dev/null` + + if test ! -d "$my_tmpdir"; then + # Failing that, at least try and use $RANDOM to avoid a race + my_tmpdir="${my_template}-${RANDOM-0}$$" + + save_mktempdir_umask=`umask` + umask 0077 + $mkdir "$my_tmpdir" + umask $save_mktempdir_umask + fi + + # If we're not in dry-run mode, bomb out on failure + test -d "$my_tmpdir" || { + $echo "cannot create temporary directory \`$my_tmpdir'" 1>&2 + exit $EXIT_FAILURE + } + fi + + $echo "X$my_tmpdir" | $Xsed +} + + +# func_win32_libid arg +# return the library type of file 'arg' +# +# Need a lot of goo to handle *both* DLLs and import libs +# Has to be a shell function in order to 'eat' the argument +# that is supplied when $file_magic_command is called. +func_win32_libid () +{ + win32_libid_type="unknown" + win32_fileres=`file -L $1 2>/dev/null` + case $win32_fileres in + *ar\ archive\ import\ library*) # definitely import + win32_libid_type="x86 archive import" + ;; + *ar\ archive*) # could be an import, or static + if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null | \ + $EGREP -e 'file format pe-i386(.*architecture: i386)?' >/dev/null ; then + win32_nmres=`eval $NM -f posix -A $1 | \ + $SED -n -e '1,100{ + / I /{ + s,.*,import, + p + q + } + }'` + case $win32_nmres in + import*) win32_libid_type="x86 archive import";; + *) win32_libid_type="x86 archive static";; + esac + fi + ;; + *DLL*) + win32_libid_type="x86 DLL" + ;; + *executable*) # but shell scripts are "executable" too... + case $win32_fileres in + *MS\ Windows\ PE\ Intel*) + win32_libid_type="x86 DLL" + ;; + esac + ;; + esac + $echo $win32_libid_type +} + + +# func_infer_tag arg +# Infer tagged configuration to use if any are available and +# if one wasn't chosen via the "--tag" command line option. +# Only attempt this if the compiler in the base compile +# command doesn't match the default compiler. +# arg is usually of the form 'gcc ...' +func_infer_tag () +{ + if test -n "$available_tags" && test -z "$tagname"; then + CC_quoted= + for arg in $CC; do + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + CC_quoted="$CC_quoted $arg" + done + case $@ in + # Blanks in the command may have been stripped by the calling shell, + # but not from the CC environment variable when configure was run. + " $CC "* | "$CC "* | " `$echo $CC` "* | "`$echo $CC` "* | " $CC_quoted"* | "$CC_quoted "* | " `$echo $CC_quoted` "* | "`$echo $CC_quoted` "*) ;; + # Blanks at the start of $base_compile will cause this to fail + # if we don't check for them as well. + *) + for z in $available_tags; do + if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then + # Evaluate the configuration. + eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`" + CC_quoted= + for arg in $CC; do + # Double-quote args containing other shell metacharacters. + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + CC_quoted="$CC_quoted $arg" + done + case "$@ " in + " $CC "* | "$CC "* | " `$echo $CC` "* | "`$echo $CC` "* | " $CC_quoted"* | "$CC_quoted "* | " `$echo $CC_quoted` "* | "`$echo $CC_quoted` "*) + # The compiler in the base compile command matches + # the one in the tagged configuration. + # Assume this is the tagged configuration we want. + tagname=$z + break + ;; + esac + fi + done + # If $tagname still isn't set, then no tagged configuration + # was found and let the user know that the "--tag" command + # line option must be used. + if test -z "$tagname"; then + $echo "$modename: unable to infer tagged configuration" + $echo "$modename: specify a tag with \`--tag'" 1>&2 + exit $EXIT_FAILURE +# else +# $echo "$modename: using $tagname tagged configuration" + fi + ;; + esac + fi +} + + +# func_extract_an_archive dir oldlib +func_extract_an_archive () +{ + f_ex_an_ar_dir="$1"; shift + f_ex_an_ar_oldlib="$1" + + $show "(cd $f_ex_an_ar_dir && $AR x $f_ex_an_ar_oldlib)" + $run eval "(cd \$f_ex_an_ar_dir && $AR x \$f_ex_an_ar_oldlib)" || exit $? + if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then + : + else + $echo "$modename: ERROR: object name conflicts: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib" 1>&2 + exit $EXIT_FAILURE + fi +} + +# func_extract_archives gentop oldlib ... +func_extract_archives () +{ + my_gentop="$1"; shift + my_oldlibs=${1+"$@"} + my_oldobjs="" + my_xlib="" + my_xabs="" + my_xdir="" + my_status="" + + $show "${rm}r $my_gentop" + $run ${rm}r "$my_gentop" + $show "$mkdir $my_gentop" + $run $mkdir "$my_gentop" + my_status=$? + if test "$my_status" -ne 0 && test ! -d "$my_gentop"; then + exit $my_status + fi + + for my_xlib in $my_oldlibs; do + # Extract the objects. + case $my_xlib in + [\\/]* | [A-Za-z]:[\\/]*) my_xabs="$my_xlib" ;; + *) my_xabs=`pwd`"/$my_xlib" ;; + esac + my_xlib=`$echo "X$my_xlib" | $Xsed -e 's%^.*/%%'` + my_xlib_u=$my_xlib + while :; do + case " $extracted_archives " in + *" $my_xlib_u "*) + extracted_serial=`expr $extracted_serial + 1` + my_xlib_u=lt$extracted_serial-$my_xlib ;; + *) break ;; + esac + done + extracted_archives="$extracted_archives $my_xlib_u" + my_xdir="$my_gentop/$my_xlib_u" + + $show "${rm}r $my_xdir" + $run ${rm}r "$my_xdir" + $show "$mkdir $my_xdir" + $run $mkdir "$my_xdir" + exit_status=$? + if test "$exit_status" -ne 0 && test ! -d "$my_xdir"; then + exit $exit_status + fi + case $host in + *-darwin*) + $show "Extracting $my_xabs" + # Do not bother doing anything if just a dry run + if test -z "$run"; then + darwin_orig_dir=`pwd` + cd $my_xdir || exit $? + darwin_archive=$my_xabs + darwin_curdir=`pwd` + darwin_base_archive=`$echo "X$darwin_archive" | $Xsed -e 's%^.*/%%'` + darwin_arches=`lipo -info "$darwin_archive" 2>/dev/null | $EGREP Architectures 2>/dev/null` + if test -n "$darwin_arches"; then + darwin_arches=`echo "$darwin_arches" | $SED -e 's/.*are://'` + darwin_arch= + $show "$darwin_base_archive has multiple architectures $darwin_arches" + for darwin_arch in $darwin_arches ; do + mkdir -p "unfat-$$/${darwin_base_archive}-${darwin_arch}" + lipo -thin $darwin_arch -output "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" "${darwin_archive}" + cd "unfat-$$/${darwin_base_archive}-${darwin_arch}" + func_extract_an_archive "`pwd`" "${darwin_base_archive}" + cd "$darwin_curdir" + $rm "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" + done # $darwin_arches + ## Okay now we have a bunch of thin objects, gotta fatten them up :) + darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print| xargs basename | sort -u | $NL2SP` + darwin_file= + darwin_files= + for darwin_file in $darwin_filelist; do + darwin_files=`find unfat-$$ -name $darwin_file -print | $NL2SP` + lipo -create -output "$darwin_file" $darwin_files + done # $darwin_filelist + ${rm}r unfat-$$ + cd "$darwin_orig_dir" + else + cd "$darwin_orig_dir" + func_extract_an_archive "$my_xdir" "$my_xabs" + fi # $darwin_arches + fi # $run + ;; + *) + func_extract_an_archive "$my_xdir" "$my_xabs" + ;; + esac + my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | $NL2SP` + done + func_extract_archives_result="$my_oldobjs" +} +# End of Shell function definitions +##################################### + +# Darwin sucks +eval std_shrext=\"$shrext_cmds\" + +disable_libs=no + +# Parse our command line options once, thoroughly. +while test "$#" -gt 0 +do + arg="$1" + shift + + case $arg in + -*=*) optarg=`$echo "X$arg" | $Xsed -e 's/[-_a-zA-Z0-9]*=//'` ;; + *) optarg= ;; + esac + + # If the previous option needs an argument, assign it. + if test -n "$prev"; then + case $prev in + execute_dlfiles) + execute_dlfiles="$execute_dlfiles $arg" + ;; + tag) + tagname="$arg" + preserve_args="${preserve_args}=$arg" + + # Check whether tagname contains only valid characters + case $tagname in + *[!-_A-Za-z0-9,/]*) + $echo "$progname: invalid tag name: $tagname" 1>&2 + exit $EXIT_FAILURE + ;; + esac + + case $tagname in + CC) + # Don't test for the "default" C tag, as we know, it's there, but + # not specially marked. + ;; + *) + if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$" < "$progpath" > /dev/null; then + taglist="$taglist $tagname" + # Evaluate the configuration. + eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$tagname'$/,/^# ### END LIBTOOL TAG CONFIG: '$tagname'$/p' < $progpath`" + else + $echo "$progname: ignoring unknown tag $tagname" 1>&2 + fi + ;; + esac + ;; + *) + eval "$prev=\$arg" + ;; + esac + + prev= + prevopt= + continue + fi + + # Have we seen a non-optional argument yet? + case $arg in + --help) + show_help=yes + ;; + + --version) + echo "\ +$PROGRAM (GNU $PACKAGE) $VERSION$TIMESTAMP + +Copyright (C) 2008 Free Software Foundation, Inc. +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + exit $? + ;; + + --config) + ${SED} -e '1,/^# ### BEGIN LIBTOOL CONFIG/d' -e '/^# ### END LIBTOOL CONFIG/,$d' $progpath + # Now print the configurations for the tags. + for tagname in $taglist; do + ${SED} -n -e "/^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$/,/^# ### END LIBTOOL TAG CONFIG: $tagname$/p" < "$progpath" + done + exit $? + ;; + + --debug) + $echo "$progname: enabling shell trace mode" + set -x + preserve_args="$preserve_args $arg" + ;; + + --dry-run | -n) + run=: + ;; + + --features) + $echo "host: $host" + if test "$build_libtool_libs" = yes; then + $echo "enable shared libraries" + else + $echo "disable shared libraries" + fi + if test "$build_old_libs" = yes; then + $echo "enable static libraries" + else + $echo "disable static libraries" + fi + exit $? + ;; + + --finish) mode="finish" ;; + + --mode) prevopt="--mode" prev=mode ;; + --mode=*) mode="$optarg" ;; + + --preserve-dup-deps) duplicate_deps="yes" ;; + + --quiet | --silent) + show=: + preserve_args="$preserve_args $arg" + ;; + + --tag) + prevopt="--tag" + prev=tag + preserve_args="$preserve_args --tag" + ;; + --tag=*) + set tag "$optarg" ${1+"$@"} + shift + prev=tag + preserve_args="$preserve_args --tag" + ;; + + -dlopen) + prevopt="-dlopen" + prev=execute_dlfiles + ;; + + -*) + $echo "$modename: unrecognized option \`$arg'" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + ;; + + *) + nonopt="$arg" + break + ;; + esac +done + +if test -n "$prevopt"; then + $echo "$modename: option \`$prevopt' requires an argument" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE +fi + +case $disable_libs in +no) + ;; +shared) + build_libtool_libs=no + build_old_libs=yes + ;; +static) + build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac` + ;; +esac + +# If this variable is set in any of the actions, the command in it +# will be execed at the end. This prevents here-documents from being +# left over by shells. +exec_cmd= + +if test -z "$show_help"; then + + # Infer the operation mode. + if test -z "$mode"; then + $echo "*** Warning: inferring the mode of operation is deprecated." 1>&2 + $echo "*** Future versions of Libtool will require --mode=MODE be specified." 1>&2 + case $nonopt in + *cc | cc* | *++ | gcc* | *-gcc* | g++* | xlc*) + mode=link + for arg + do + case $arg in + -c) + mode=compile + break + ;; + esac + done + ;; + *db | *dbx | *strace | *truss) + mode=execute + ;; + *install*|cp|mv) + mode=install + ;; + *rm) + mode=uninstall + ;; + *) + # If we have no mode, but dlfiles were specified, then do execute mode. + test -n "$execute_dlfiles" && mode=execute + + # Just use the default operation mode. + if test -z "$mode"; then + if test -n "$nonopt"; then + $echo "$modename: warning: cannot infer operation mode from \`$nonopt'" 1>&2 + else + $echo "$modename: warning: cannot infer operation mode without MODE-ARGS" 1>&2 + fi + fi + ;; + esac + fi + + # Only execute mode is allowed to have -dlopen flags. + if test -n "$execute_dlfiles" && test "$mode" != execute; then + $echo "$modename: unrecognized option \`-dlopen'" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + # Change the help message to a mode-specific one. + generic_help="$help" + help="Try \`$modename --help --mode=$mode' for more information." + + # These modes are in order of execution frequency so that they run quickly. + case $mode in + # libtool compile mode + compile) + modename="$modename: compile" + # Get the compilation command and the source file. + base_compile= + srcfile="$nonopt" # always keep a non-empty value in "srcfile" + suppress_opt=yes + suppress_output= + arg_mode=normal + libobj= + later= + + for arg + do + case $arg_mode in + arg ) + # do not "continue". Instead, add this to base_compile + lastarg="$arg" + arg_mode=normal + ;; + + target ) + libobj="$arg" + arg_mode=normal + continue + ;; + + normal ) + # Accept any command-line options. + case $arg in + -o) + if test -n "$libobj" ; then + $echo "$modename: you cannot specify \`-o' more than once" 1>&2 + exit $EXIT_FAILURE + fi + arg_mode=target + continue + ;; + + -static | -prefer-pic | -prefer-non-pic) + later="$later $arg" + continue + ;; + + -no-suppress) + suppress_opt=no + continue + ;; + + -Xcompiler) + arg_mode=arg # the next one goes into the "base_compile" arg list + continue # The current "srcfile" will either be retained or + ;; # replaced later. I would guess that would be a bug. + + -Wc,*) + args=`$echo "X$arg" | $Xsed -e "s/^-Wc,//"` + lastarg= + save_ifs="$IFS"; IFS=',' + for arg in $args; do + IFS="$save_ifs" + + # Double-quote args containing other shell metacharacters. + # Many Bourne shells cannot handle close brackets correctly + # in scan sets, so we specify it separately. + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + lastarg="$lastarg $arg" + done + IFS="$save_ifs" + lastarg=`$echo "X$lastarg" | $Xsed -e "s/^ //"` + + # Add the arguments to base_compile. + base_compile="$base_compile $lastarg" + continue + ;; + + * ) + # Accept the current argument as the source file. + # The previous "srcfile" becomes the current argument. + # + lastarg="$srcfile" + srcfile="$arg" + ;; + esac # case $arg + ;; + esac # case $arg_mode + + # Aesthetically quote the previous argument. + lastarg=`$echo "X$lastarg" | $Xsed -e "$sed_quote_subst"` + + case $lastarg in + # Double-quote args containing other shell metacharacters. + # Many Bourne shells cannot handle close brackets correctly + # in scan sets, and some SunOS ksh mistreat backslash-escaping + # in scan sets (worked around with variable expansion), + # and furthermore cannot handle '|' '&' '(' ')' in scan sets + # at all, so we specify them separately. + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + lastarg="\"$lastarg\"" + ;; + esac + + base_compile="$base_compile $lastarg" + done # for arg + + case $arg_mode in + arg) + $echo "$modename: you must specify an argument for -Xcompile" + exit $EXIT_FAILURE + ;; + target) + $echo "$modename: you must specify a target with \`-o'" 1>&2 + exit $EXIT_FAILURE + ;; + *) + # Get the name of the library object. + [ -z "$libobj" ] && libobj=`$echo "X$srcfile" | $Xsed -e 's%^.*/%%'` + ;; + esac + + # Recognize several different file suffixes. + # If the user specifies -o file.o, it is replaced with file.lo + xform='[cCFSifmso]' + case $libobj in + *.ada) xform=ada ;; + *.adb) xform=adb ;; + *.ads) xform=ads ;; + *.asm) xform=asm ;; + *.c++) xform=c++ ;; + *.cc) xform=cc ;; + *.ii) xform=ii ;; + *.class) xform=class ;; + *.cpp) xform=cpp ;; + *.cxx) xform=cxx ;; + *.[fF][09]?) xform=[fF][09]. ;; + *.for) xform=for ;; + *.java) xform=java ;; + *.obj) xform=obj ;; + *.sx) xform=sx ;; + esac + + libobj=`$echo "X$libobj" | $Xsed -e "s/\.$xform$/.lo/"` + + case $libobj in + *.lo) obj=`$echo "X$libobj" | $Xsed -e "$lo2o"` ;; + *) + $echo "$modename: cannot determine name of library object from \`$libobj'" 1>&2 + exit $EXIT_FAILURE + ;; + esac + + func_infer_tag $base_compile + + for arg in $later; do + case $arg in + -static) + build_old_libs=yes + continue + ;; + + -prefer-pic) + pic_mode=yes + continue + ;; + + -prefer-non-pic) + pic_mode=no + continue + ;; + esac + done + + qlibobj=`$echo "X$libobj" | $Xsed -e "$sed_quote_subst"` + case $qlibobj in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + qlibobj="\"$qlibobj\"" ;; + esac + test "X$libobj" != "X$qlibobj" \ + && $echo "X$libobj" | grep '[]~#^*{};<>?"'"'"' &()|`$[]' \ + && $echo "$modename: libobj name \`$libobj' may not contain shell special characters." + objname=`$echo "X$obj" | $Xsed -e 's%^.*/%%'` + xdir=`$echo "X$obj" | $Xsed -e 's%/[^/]*$%%'` + if test "X$xdir" = "X$obj"; then + xdir= + else + xdir=$xdir/ + fi + lobj=${xdir}$objdir/$objname + + if test -z "$base_compile"; then + $echo "$modename: you must specify a compilation command" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + # Delete any leftover library objects. + if test "$build_old_libs" = yes; then + removelist="$obj $lobj $libobj ${libobj}T" + else + removelist="$lobj $libobj ${libobj}T" + fi + + $run $rm $removelist + trap "$run $rm $removelist; exit $EXIT_FAILURE" 1 2 15 + + # On Cygwin there's no "real" PIC flag so we must build both object types + case $host_os in + cygwin* | mingw* | pw32* | os2*) + pic_mode=default + ;; + esac + if test "$pic_mode" = no && test "$deplibs_check_method" != pass_all; then + # non-PIC code in shared libraries is not supported + pic_mode=default + fi + + # Calculate the filename of the output object if compiler does + # not support -o with -c + if test "$compiler_c_o" = no; then + output_obj=`$echo "X$srcfile" | $Xsed -e 's%^.*/%%' -e 's%\.[^.]*$%%'`.${objext} + lockfile="$output_obj.lock" + removelist="$removelist $output_obj $lockfile" + trap "$run $rm $removelist; exit $EXIT_FAILURE" 1 2 15 + else + output_obj= + need_locks=no + lockfile= + fi + + # Lock this critical section if it is needed + # We use this script file to make the link, it avoids creating a new file + if test "$need_locks" = yes; then + until $run ln "$progpath" "$lockfile" 2>/dev/null; do + $show "Waiting for $lockfile to be removed" + sleep 2 + done + elif test "$need_locks" = warn; then + if test -f "$lockfile"; then + $echo "\ +*** ERROR, $lockfile exists and contains: +`cat $lockfile 2>/dev/null` + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $run $rm $removelist + exit $EXIT_FAILURE + fi + $echo "$srcfile" > "$lockfile" + fi + + if test -n "$fix_srcfile_path"; then + eval srcfile=\"$fix_srcfile_path\" + fi + qsrcfile=`$echo "X$srcfile" | $Xsed -e "$sed_quote_subst"` + case $qsrcfile in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + qsrcfile="\"$qsrcfile\"" ;; + esac + + $run $rm "$libobj" "${libobj}T" + + # Create a libtool object file (analogous to a ".la" file), + # but don't create it if we're doing a dry run. + test -z "$run" && cat > ${libobj}T </dev/null`" != "X$srcfile"; then + $echo "\ +*** ERROR, $lockfile contains: +`cat $lockfile 2>/dev/null` + +but it should contain: +$srcfile + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $run $rm $removelist + exit $EXIT_FAILURE + fi + + # Just move the object if needed, then go on to compile the next one + if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then + $show "$mv $output_obj $lobj" + if $run $mv $output_obj $lobj; then : + else + error=$? + $run $rm $removelist + exit $error + fi + fi + + # Append the name of the PIC object to the libtool object file. + test -z "$run" && cat >> ${libobj}T <> ${libobj}T </dev/null`" != "X$srcfile"; then + $echo "\ +*** ERROR, $lockfile contains: +`cat $lockfile 2>/dev/null` + +but it should contain: +$srcfile + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $run $rm $removelist + exit $EXIT_FAILURE + fi + + # Just move the object if needed + if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then + $show "$mv $output_obj $obj" + if $run $mv $output_obj $obj; then : + else + error=$? + $run $rm $removelist + exit $error + fi + fi + + # Append the name of the non-PIC object the libtool object file. + # Only append if the libtool object file exists. + test -z "$run" && cat >> ${libobj}T <> ${libobj}T <&2 + fi + if test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + prefer_static_libs=yes + ;; + -static) + if test -z "$pic_flag" && test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + prefer_static_libs=built + ;; + -static-libtool-libs) + if test -z "$pic_flag" && test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + prefer_static_libs=yes + ;; + esac + build_libtool_libs=no + build_old_libs=yes + break + ;; + esac + done + + # See if our shared archives depend on static archives. + test -n "$old_archive_from_new_cmds" && build_old_libs=yes + + # Go through the arguments, transforming them on the way. + while test "$#" -gt 0; do + arg="$1" + shift + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + qarg=\"`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`\" ### testsuite: skip nested quoting test + ;; + *) qarg=$arg ;; + esac + libtool_args="$libtool_args $qarg" + + # If the previous option needs an argument, assign it. + if test -n "$prev"; then + case $prev in + output) + compile_command="$compile_command @OUTPUT@" + finalize_command="$finalize_command @OUTPUT@" + ;; + esac + + case $prev in + dlfiles|dlprefiles) + if test "$preload" = no; then + # Add the symbol object into the linking commands. + compile_command="$compile_command @SYMFILE@" + finalize_command="$finalize_command @SYMFILE@" + preload=yes + fi + case $arg in + *.la | *.lo) ;; # We handle these cases below. + force) + if test "$dlself" = no; then + dlself=needless + export_dynamic=yes + fi + prev= + continue + ;; + self) + if test "$prev" = dlprefiles; then + dlself=yes + elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then + dlself=yes + else + dlself=needless + export_dynamic=yes + fi + prev= + continue + ;; + *) + if test "$prev" = dlfiles; then + dlfiles="$dlfiles $arg" + else + dlprefiles="$dlprefiles $arg" + fi + prev= + continue + ;; + esac + ;; + expsyms) + export_symbols="$arg" + if test ! -f "$arg"; then + $echo "$modename: symbol file \`$arg' does not exist" + exit $EXIT_FAILURE + fi + prev= + continue + ;; + expsyms_regex) + export_symbols_regex="$arg" + prev= + continue + ;; + inst_prefix) + inst_prefix_dir="$arg" + prev= + continue + ;; + precious_regex) + precious_files_regex="$arg" + prev= + continue + ;; + release) + release="-$arg" + prev= + continue + ;; + objectlist) + if test -f "$arg"; then + save_arg=$arg + moreargs= + for fil in `cat $save_arg` + do +# moreargs="$moreargs $fil" + arg=$fil + # A libtool-controlled object. + + # Check to see that this really is a libtool object. + if (${SED} -e '2q' $arg | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + pic_object= + non_pic_object= + + # Read the .lo file + # If there is no directory component, then add one. + case $arg in + */* | *\\*) . $arg ;; + *) . ./$arg ;; + esac + + if test -z "$pic_object" || \ + test -z "$non_pic_object" || + test "$pic_object" = none && \ + test "$non_pic_object" = none; then + $echo "$modename: cannot find name of object for \`$arg'" 1>&2 + exit $EXIT_FAILURE + fi + + # Extract subdirectory from the argument. + xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'` + if test "X$xdir" = "X$arg"; then + xdir= + else + xdir="$xdir/" + fi + + if test "$pic_object" != none; then + # Prepend the subdirectory the object is found in. + pic_object="$xdir$pic_object" + + if test "$prev" = dlfiles; then + if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then + dlfiles="$dlfiles $pic_object" + prev= + continue + else + # If libtool objects are unsupported, then we need to preload. + prev=dlprefiles + fi + fi + + # CHECK ME: I think I busted this. -Ossama + if test "$prev" = dlprefiles; then + # Preload the old-style object. + dlprefiles="$dlprefiles $pic_object" + prev= + fi + + # A PIC object. + libobjs="$libobjs $pic_object" + arg="$pic_object" + fi + + # Non-PIC object. + if test "$non_pic_object" != none; then + # Prepend the subdirectory the object is found in. + non_pic_object="$xdir$non_pic_object" + + # A standard non-PIC object + non_pic_objects="$non_pic_objects $non_pic_object" + if test -z "$pic_object" || test "$pic_object" = none ; then + arg="$non_pic_object" + fi + else + # If the PIC object exists, use it instead. + # $xdir was prepended to $pic_object above. + non_pic_object="$pic_object" + non_pic_objects="$non_pic_objects $non_pic_object" + fi + else + # Only an error if not doing a dry-run. + if test -z "$run"; then + $echo "$modename: \`$arg' is not a valid libtool object" 1>&2 + exit $EXIT_FAILURE + else + # Dry-run case. + + # Extract subdirectory from the argument. + xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'` + if test "X$xdir" = "X$arg"; then + xdir= + else + xdir="$xdir/" + fi + + pic_object=`$echo "X${xdir}${objdir}/${arg}" | $Xsed -e "$lo2o"` + non_pic_object=`$echo "X${xdir}${arg}" | $Xsed -e "$lo2o"` + libobjs="$libobjs $pic_object" + non_pic_objects="$non_pic_objects $non_pic_object" + fi + fi + done + else + $echo "$modename: link input file \`$save_arg' does not exist" + exit $EXIT_FAILURE + fi + arg=$save_arg + prev= + continue + ;; + rpath | xrpath) + # We need an absolute path. + case $arg in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + $echo "$modename: only absolute run-paths are allowed" 1>&2 + exit $EXIT_FAILURE + ;; + esac + if test "$prev" = rpath; then + case "$rpath " in + *" $arg "*) ;; + *) rpath="$rpath $arg" ;; + esac + else + case "$xrpath " in + *" $arg "*) ;; + *) xrpath="$xrpath $arg" ;; + esac + fi + prev= + continue + ;; + xcompiler) + compiler_flags="$compiler_flags $qarg" + prev= + compile_command="$compile_command $qarg" + finalize_command="$finalize_command $qarg" + continue + ;; + xlinker) + linker_flags="$linker_flags $qarg" + compiler_flags="$compiler_flags $wl$qarg" + prev= + compile_command="$compile_command $wl$qarg" + finalize_command="$finalize_command $wl$qarg" + continue + ;; + xcclinker) + linker_flags="$linker_flags $qarg" + compiler_flags="$compiler_flags $qarg" + prev= + compile_command="$compile_command $qarg" + finalize_command="$finalize_command $qarg" + continue + ;; + shrext) + shrext_cmds="$arg" + prev= + continue + ;; + darwin_framework|darwin_framework_skip) + test "$prev" = "darwin_framework" && compiler_flags="$compiler_flags $arg" + compile_command="$compile_command $arg" + finalize_command="$finalize_command $arg" + prev= + continue + ;; + *) + eval "$prev=\"\$arg\"" + prev= + continue + ;; + esac + fi # test -n "$prev" + + prevarg="$arg" + + case $arg in + -all-static) + if test -n "$link_static_flag"; then + compile_command="$compile_command $link_static_flag" + finalize_command="$finalize_command $link_static_flag" + fi + continue + ;; + + -allow-undefined) + # FIXME: remove this flag sometime in the future. + $echo "$modename: \`-allow-undefined' is deprecated because it is the default" 1>&2 + continue + ;; + + -avoid-version) + avoid_version=yes + continue + ;; + + -dlopen) + prev=dlfiles + continue + ;; + + -dlpreopen) + prev=dlprefiles + continue + ;; + + -export-dynamic) + export_dynamic=yes + continue + ;; + + -export-symbols | -export-symbols-regex) + if test -n "$export_symbols" || test -n "$export_symbols_regex"; then + $echo "$modename: more than one -exported-symbols argument is not allowed" + exit $EXIT_FAILURE + fi + if test "X$arg" = "X-export-symbols"; then + prev=expsyms + else + prev=expsyms_regex + fi + continue + ;; + + -framework|-arch|-isysroot) + case " $CC " in + *" ${arg} ${1} "* | *" ${arg} ${1} "*) + prev=darwin_framework_skip ;; + *) compiler_flags="$compiler_flags $arg" + prev=darwin_framework ;; + esac + compile_command="$compile_command $arg" + finalize_command="$finalize_command $arg" + continue + ;; + + -inst-prefix-dir) + prev=inst_prefix + continue + ;; + + # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:* + # so, if we see these flags be careful not to treat them like -L + -L[A-Z][A-Z]*:*) + case $with_gcc/$host in + no/*-*-irix* | /*-*-irix*) + compile_command="$compile_command $arg" + finalize_command="$finalize_command $arg" + ;; + esac + continue + ;; + + -L*) + dir=`$echo "X$arg" | $Xsed -e 's/^-L//'` + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + absdir=`cd "$dir" && pwd` + if test -z "$absdir"; then + $echo "$modename: cannot determine absolute directory name of \`$dir'" 1>&2 + absdir="$dir" + notinst_path="$notinst_path $dir" + fi + dir="$absdir" + ;; + esac + case "$deplibs " in + *" -L$dir "*) ;; + *) + deplibs="$deplibs -L$dir" + lib_search_path="$lib_search_path $dir" + ;; + esac + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*) + testbindir=`$echo "X$dir" | $Xsed -e 's*/lib$*/bin*'` + case :$dllsearchpath: in + *":$dir:"*) ;; + *) dllsearchpath="$dllsearchpath:$dir";; + esac + case :$dllsearchpath: in + *":$testbindir:"*) ;; + *) dllsearchpath="$dllsearchpath:$testbindir";; + esac + ;; + esac + continue + ;; + + -l*) + if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos*) + # These systems don't actually have a C or math library (as such) + continue + ;; + *-*-os2*) + # These systems don't actually have a C library (as such) + test "X$arg" = "X-lc" && continue + ;; + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) + # Do not include libc due to us having libc/libc_r. + test "X$arg" = "X-lc" && continue + ;; + *-*-rhapsody* | *-*-darwin1.[012]) + # Rhapsody C and math libraries are in the System framework + deplibs="$deplibs -framework System" + continue + ;; + *-*-sco3.2v5* | *-*-sco5v6*) + # Causes problems with __ctype + test "X$arg" = "X-lc" && continue + ;; + *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) + # Compiler inserts libc in the correct place for threads to work + test "X$arg" = "X-lc" && continue + ;; + esac + elif test "X$arg" = "X-lc_r"; then + case $host in + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) + # Do not include libc_r directly, use -pthread flag. + continue + ;; + esac + fi + deplibs="$deplibs $arg" + continue + ;; + + # Tru64 UNIX uses -model [arg] to determine the layout of C++ + # classes, name mangling, and exception handling. + -model) + compile_command="$compile_command $arg" + compiler_flags="$compiler_flags $arg" + finalize_command="$finalize_command $arg" + prev=xcompiler + continue + ;; + + -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe|-threads) + compiler_flags="$compiler_flags $arg" + compile_command="$compile_command $arg" + finalize_command="$finalize_command $arg" + continue + ;; + + -multi_module) + single_module="${wl}-multi_module" + continue + ;; + + -module) + module=yes + continue + ;; + + # -64, -mips[0-9] enable 64-bit mode on the SGI compiler + # -r[0-9][0-9]* specifies the processor on the SGI compiler + # -xarch=*, -xtarget=* enable 64-bit mode on the Sun compiler + # +DA*, +DD* enable 64-bit mode on the HP compiler + # -q* pass through compiler args for the IBM compiler + # -m* pass through architecture-specific compiler args for GCC + # -m*, -t[45]*, -txscale* pass through architecture-specific + # compiler args for GCC + # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC + # -F/path gives path to uninstalled frameworks, gcc on darwin + # @file GCC response files + -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \ + -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*) + + # Unknown arguments in both finalize_command and compile_command need + # to be aesthetically quoted because they are evaled later. + arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + compile_command="$compile_command $arg" + finalize_command="$finalize_command $arg" + compiler_flags="$compiler_flags $arg" + continue + ;; + + -shrext) + prev=shrext + continue + ;; + + -no-fast-install) + fast_install=no + continue + ;; + + -no-install) + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-darwin*) + # The PATH hackery in wrapper scripts is required on Windows + # and Darwin in order for the loader to find any dlls it needs. + $echo "$modename: warning: \`-no-install' is ignored for $host" 1>&2 + $echo "$modename: warning: assuming \`-no-fast-install' instead" 1>&2 + fast_install=no + ;; + *) no_install=yes ;; + esac + continue + ;; + + -no-undefined) + allow_undefined=no + continue + ;; + + -objectlist) + prev=objectlist + continue + ;; + + -o) prev=output ;; + + -precious-files-regex) + prev=precious_regex + continue + ;; + + -release) + prev=release + continue + ;; + + -rpath) + prev=rpath + continue + ;; + + -R) + prev=xrpath + continue + ;; + + -R*) + dir=`$echo "X$arg" | $Xsed -e 's/^-R//'` + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + $echo "$modename: only absolute run-paths are allowed" 1>&2 + exit $EXIT_FAILURE + ;; + esac + case "$xrpath " in + *" $dir "*) ;; + *) xrpath="$xrpath $dir" ;; + esac + continue + ;; + + -static | -static-libtool-libs) + # The effects of -static are defined in a previous loop. + # We used to do the same as -all-static on platforms that + # didn't have a PIC flag, but the assumption that the effects + # would be equivalent was wrong. It would break on at least + # Digital Unix and AIX. + continue + ;; + + -thread-safe) + thread_safe=yes + continue + ;; + + -version-info) + prev=vinfo + continue + ;; + -version-number) + prev=vinfo + vinfo_number=yes + continue + ;; + + -Wc,*) + args=`$echo "X$arg" | $Xsed -e "$sed_quote_subst" -e 's/^-Wc,//'` + arg= + save_ifs="$IFS"; IFS=',' + for flag in $args; do + IFS="$save_ifs" + case $flag in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + flag="\"$flag\"" + ;; + esac + arg="$arg $wl$flag" + compiler_flags="$compiler_flags $flag" + done + IFS="$save_ifs" + arg=`$echo "X$arg" | $Xsed -e "s/^ //"` + ;; + + -Wl,*) + args=`$echo "X$arg" | $Xsed -e "$sed_quote_subst" -e 's/^-Wl,//'` + arg= + save_ifs="$IFS"; IFS=',' + for flag in $args; do + IFS="$save_ifs" + case $flag in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + flag="\"$flag\"" + ;; + esac + arg="$arg $wl$flag" + compiler_flags="$compiler_flags $wl$flag" + linker_flags="$linker_flags $flag" + done + IFS="$save_ifs" + arg=`$echo "X$arg" | $Xsed -e "s/^ //"` + ;; + + -Xcompiler) + prev=xcompiler + continue + ;; + + -Xlinker) + prev=xlinker + continue + ;; + + -XCClinker) + prev=xcclinker + continue + ;; + + # Some other compiler flag. + -* | +*) + # Unknown arguments in both finalize_command and compile_command need + # to be aesthetically quoted because they are evaled later. + arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + ;; + + *.$objext) + # A standard object. + objs="$objs $arg" + ;; + + *.lo) + # A libtool-controlled object. + + # Check to see that this really is a libtool object. + if (${SED} -e '2q' $arg | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + pic_object= + non_pic_object= + + # Read the .lo file + # If there is no directory component, then add one. + case $arg in + */* | *\\*) . $arg ;; + *) . ./$arg ;; + esac + + if test -z "$pic_object" || \ + test -z "$non_pic_object" || + test "$pic_object" = none && \ + test "$non_pic_object" = none; then + $echo "$modename: cannot find name of object for \`$arg'" 1>&2 + exit $EXIT_FAILURE + fi + + # Extract subdirectory from the argument. + xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'` + if test "X$xdir" = "X$arg"; then + xdir= + else + xdir="$xdir/" + fi + + if test "$pic_object" != none; then + # Prepend the subdirectory the object is found in. + pic_object="$xdir$pic_object" + + if test "$prev" = dlfiles; then + if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then + dlfiles="$dlfiles $pic_object" + prev= + continue + else + # If libtool objects are unsupported, then we need to preload. + prev=dlprefiles + fi + fi + + # CHECK ME: I think I busted this. -Ossama + if test "$prev" = dlprefiles; then + # Preload the old-style object. + dlprefiles="$dlprefiles $pic_object" + prev= + fi + + # A PIC object. + libobjs="$libobjs $pic_object" + arg="$pic_object" + fi + + # Non-PIC object. + if test "$non_pic_object" != none; then + # Prepend the subdirectory the object is found in. + non_pic_object="$xdir$non_pic_object" + + # A standard non-PIC object + non_pic_objects="$non_pic_objects $non_pic_object" + if test -z "$pic_object" || test "$pic_object" = none ; then + arg="$non_pic_object" + fi + else + # If the PIC object exists, use it instead. + # $xdir was prepended to $pic_object above. + non_pic_object="$pic_object" + non_pic_objects="$non_pic_objects $non_pic_object" + fi + else + # Only an error if not doing a dry-run. + if test -z "$run"; then + $echo "$modename: \`$arg' is not a valid libtool object" 1>&2 + exit $EXIT_FAILURE + else + # Dry-run case. + + # Extract subdirectory from the argument. + xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'` + if test "X$xdir" = "X$arg"; then + xdir= + else + xdir="$xdir/" + fi + + pic_object=`$echo "X${xdir}${objdir}/${arg}" | $Xsed -e "$lo2o"` + non_pic_object=`$echo "X${xdir}${arg}" | $Xsed -e "$lo2o"` + libobjs="$libobjs $pic_object" + non_pic_objects="$non_pic_objects $non_pic_object" + fi + fi + ;; + + *.$libext) + # An archive. + deplibs="$deplibs $arg" + old_deplibs="$old_deplibs $arg" + continue + ;; + + *.la) + # A libtool-controlled library. + + if test "$prev" = dlfiles; then + # This library was specified with -dlopen. + dlfiles="$dlfiles $arg" + prev= + elif test "$prev" = dlprefiles; then + # The library was specified with -dlpreopen. + dlprefiles="$dlprefiles $arg" + prev= + else + deplibs="$deplibs $arg" + fi + continue + ;; + + # Some other compiler argument. + *) + # Unknown arguments in both finalize_command and compile_command need + # to be aesthetically quoted because they are evaled later. + arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + ;; + esac # arg + + # Now actually substitute the argument into the commands. + if test -n "$arg"; then + compile_command="$compile_command $arg" + finalize_command="$finalize_command $arg" + fi + done # argument parsing loop + + if test -n "$prev"; then + $echo "$modename: the \`$prevarg' option requires an argument" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then + eval arg=\"$export_dynamic_flag_spec\" + compile_command="$compile_command $arg" + finalize_command="$finalize_command $arg" + fi + + oldlibs= + # calculate the name of the file, without its directory + outputname=`$echo "X$output" | $Xsed -e 's%^.*/%%'` + libobjs_save="$libobjs" + + if test -n "$shlibpath_var"; then + # get the directories listed in $shlibpath_var + eval shlib_search_path=\`\$echo \"X\${$shlibpath_var}\" \| \$Xsed -e \'s/:/ /g\'\` + else + shlib_search_path= + fi + eval sys_lib_search_path=\"$sys_lib_search_path_spec\" + eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\" + + output_objdir=`$echo "X$output" | $Xsed -e 's%/[^/]*$%%'` + if test "X$output_objdir" = "X$output"; then + output_objdir="$objdir" + else + output_objdir="$output_objdir/$objdir" + fi + # Create the object directory. + if test ! -d "$output_objdir"; then + $show "$mkdir $output_objdir" + $run $mkdir $output_objdir + exit_status=$? + if test "$exit_status" -ne 0 && test ! -d "$output_objdir"; then + exit $exit_status + fi + fi + + # Determine the type of output + case $output in + "") + $echo "$modename: you must specify an output file" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + ;; + *.$libext) linkmode=oldlib ;; + *.lo | *.$objext) linkmode=obj ;; + *.la) linkmode=lib ;; + *) linkmode=prog ;; # Anything else should be a program. + esac + + case $host in + *cygwin* | *mingw* | *pw32*) + # don't eliminate duplications in $postdeps and $predeps + duplicate_compiler_generated_deps=yes + ;; + *) + duplicate_compiler_generated_deps=$duplicate_deps + ;; + esac + specialdeplibs= + + libs= + # Find all interdependent deplibs by searching for libraries + # that are linked more than once (e.g. -la -lb -la) + for deplib in $deplibs; do + if test "X$duplicate_deps" = "Xyes" ; then + case "$libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + fi + libs="$libs $deplib" + done + + if test "$linkmode" = lib; then + libs="$predeps $libs $compiler_lib_search_path $postdeps" + + # Compute libraries that are listed more than once in $predeps + # $postdeps and mark them as special (i.e., whose duplicates are + # not to be eliminated). + pre_post_deps= + if test "X$duplicate_compiler_generated_deps" = "Xyes" ; then + for pre_post_dep in $predeps $postdeps; do + case "$pre_post_deps " in + *" $pre_post_dep "*) specialdeplibs="$specialdeplibs $pre_post_deps" ;; + esac + pre_post_deps="$pre_post_deps $pre_post_dep" + done + fi + pre_post_deps= + fi + + deplibs= + newdependency_libs= + newlib_search_path= + need_relink=no # whether we're linking any uninstalled libtool libraries + notinst_deplibs= # not-installed libtool libraries + case $linkmode in + lib) + passes="conv link" + for file in $dlfiles $dlprefiles; do + case $file in + *.la) ;; + *) + $echo "$modename: libraries can \`-dlopen' only libtool libraries: $file" 1>&2 + exit $EXIT_FAILURE + ;; + esac + done + ;; + prog) + compile_deplibs= + finalize_deplibs= + alldeplibs=no + newdlfiles= + newdlprefiles= + passes="conv scan dlopen dlpreopen link" + ;; + *) passes="conv" + ;; + esac + for pass in $passes; do + if test "$linkmode,$pass" = "lib,link" || + test "$linkmode,$pass" = "prog,scan"; then + libs="$deplibs" + deplibs= + fi + if test "$linkmode" = prog; then + case $pass in + dlopen) libs="$dlfiles" ;; + dlpreopen) libs="$dlprefiles" ;; + link) libs="$deplibs %DEPLIBS% $dependency_libs" ;; + esac + fi + if test "$pass" = dlopen; then + # Collect dlpreopened libraries + save_deplibs="$deplibs" + deplibs= + fi + for deplib in $libs; do + lib= + found=no + case $deplib in + -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe|-threads) + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + compiler_flags="$compiler_flags $deplib" + fi + continue + ;; + -l*) + if test "$linkmode" != lib && test "$linkmode" != prog; then + $echo "$modename: warning: \`-l' is ignored for archives/objects" 1>&2 + continue + fi + name=`$echo "X$deplib" | $Xsed -e 's/^-l//'` + if test "$linkmode" = lib; then + searchdirs="$newlib_search_path $lib_search_path $compiler_lib_search_dirs $sys_lib_search_path $shlib_search_path" + else + searchdirs="$newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path" + fi + for searchdir in $searchdirs; do + for search_ext in .la $std_shrext .so .a; do + # Search the libtool library + lib="$searchdir/lib${name}${search_ext}" + if test -f "$lib"; then + if test "$search_ext" = ".la"; then + found=yes + else + found=no + fi + break 2 + fi + done + done + if test "$found" != yes; then + # deplib doesn't seem to be a libtool library + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" + fi + continue + else # deplib is a libtool library + # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib, + # We need to do some special things here, and not later. + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + case " $predeps $postdeps " in + *" $deplib "*) + if (${SED} -e '2q' $lib | + grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + library_names= + old_library= + case $lib in + */* | *\\*) . $lib ;; + *) . ./$lib ;; + esac + for l in $old_library $library_names; do + ll="$l" + done + if test "X$ll" = "X$old_library" ; then # only static version available + found=no + ladir=`$echo "X$lib" | $Xsed -e 's%/[^/]*$%%'` + test "X$ladir" = "X$lib" && ladir="." + lib=$ladir/$old_library + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" + fi + continue + fi + fi + ;; + *) ;; + esac + fi + fi + ;; # -l + -L*) + case $linkmode in + lib) + deplibs="$deplib $deplibs" + test "$pass" = conv && continue + newdependency_libs="$deplib $newdependency_libs" + newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'` + ;; + prog) + if test "$pass" = conv; then + deplibs="$deplib $deplibs" + continue + fi + if test "$pass" = scan; then + deplibs="$deplib $deplibs" + else + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + fi + newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'` + ;; + *) + $echo "$modename: warning: \`-L' is ignored for archives/objects" 1>&2 + ;; + esac # linkmode + continue + ;; # -L + -R*) + if test "$pass" = link; then + dir=`$echo "X$deplib" | $Xsed -e 's/^-R//'` + # Make sure the xrpath contains only unique directories. + case "$xrpath " in + *" $dir "*) ;; + *) xrpath="$xrpath $dir" ;; + esac + fi + deplibs="$deplib $deplibs" + continue + ;; + *.la) lib="$deplib" ;; + *.$libext) + if test "$pass" = conv; then + deplibs="$deplib $deplibs" + continue + fi + case $linkmode in + lib) + valid_a_lib=no + case $deplibs_check_method in + match_pattern*) + set dummy $deplibs_check_method + match_pattern_regex=`expr "$deplibs_check_method" : "$2 \(.*\)"` + if eval $echo \"$deplib\" 2>/dev/null \ + | $SED 10q \ + | $EGREP "$match_pattern_regex" > /dev/null; then + valid_a_lib=yes + fi + ;; + pass_all) + valid_a_lib=yes + ;; + esac + if test "$valid_a_lib" != yes; then + $echo + $echo "*** Warning: Trying to link with static lib archive $deplib." + $echo "*** I have the capability to make that library automatically link in when" + $echo "*** you link to this library. But I can only do this if you have a" + $echo "*** shared version of the library, which you do not appear to have" + $echo "*** because the file extensions .$libext of this argument makes me believe" + $echo "*** that it is just a static archive that I should not used here." + else + $echo + $echo "*** Warning: Linking the shared library $output against the" + $echo "*** static library $deplib is not portable!" + deplibs="$deplib $deplibs" + fi + continue + ;; + prog) + if test "$pass" != link; then + deplibs="$deplib $deplibs" + else + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + fi + continue + ;; + esac # linkmode + ;; # *.$libext + *.lo | *.$objext) + if test "$pass" = conv; then + deplibs="$deplib $deplibs" + elif test "$linkmode" = prog; then + if test "$pass" = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then + # If there is no dlopen support or we're linking statically, + # we need to preload. + newdlprefiles="$newdlprefiles $deplib" + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + newdlfiles="$newdlfiles $deplib" + fi + fi + continue + ;; + %DEPLIBS%) + alldeplibs=yes + continue + ;; + esac # case $deplib + if test "$found" = yes || test -f "$lib"; then : + else + $echo "$modename: cannot find the library \`$lib' or unhandled argument \`$deplib'" 1>&2 + exit $EXIT_FAILURE + fi + + # Check to see that this really is a libtool archive. + if (${SED} -e '2q' $lib | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then : + else + $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 + exit $EXIT_FAILURE + fi + + ladir=`$echo "X$lib" | $Xsed -e 's%/[^/]*$%%'` + test "X$ladir" = "X$lib" && ladir="." + + dlname= + dlopen= + dlpreopen= + libdir= + library_names= + old_library= + # If the library was installed with an old release of libtool, + # it will not redefine variables installed, or shouldnotlink + installed=yes + shouldnotlink=no + avoidtemprpath= + + + # Read the .la file + case $lib in + */* | *\\*) . $lib ;; + *) . ./$lib ;; + esac + + if test "$linkmode,$pass" = "lib,link" || + test "$linkmode,$pass" = "prog,scan" || + { test "$linkmode" != prog && test "$linkmode" != lib; }; then + test -n "$dlopen" && dlfiles="$dlfiles $dlopen" + test -n "$dlpreopen" && dlprefiles="$dlprefiles $dlpreopen" + fi + + if test "$pass" = conv; then + # Only check for convenience libraries + deplibs="$lib $deplibs" + if test -z "$libdir"; then + if test -z "$old_library"; then + $echo "$modename: cannot find name of link library for \`$lib'" 1>&2 + exit $EXIT_FAILURE + fi + # It is a libtool convenience library, so add in its objects. + convenience="$convenience $ladir/$objdir/$old_library" + old_convenience="$old_convenience $ladir/$objdir/$old_library" + tmp_libs= + for deplib in $dependency_libs; do + deplibs="$deplib $deplibs" + if test "X$duplicate_deps" = "Xyes" ; then + case "$tmp_libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + fi + tmp_libs="$tmp_libs $deplib" + done + elif test "$linkmode" != prog && test "$linkmode" != lib; then + $echo "$modename: \`$lib' is not a convenience library" 1>&2 + exit $EXIT_FAILURE + fi + continue + fi # $pass = conv + + + # Get the name of the library we link against. + linklib= + for l in $old_library $library_names; do + linklib="$l" + done + if test -z "$linklib"; then + $echo "$modename: cannot find name of link library for \`$lib'" 1>&2 + exit $EXIT_FAILURE + fi + + # This library was specified with -dlopen. + if test "$pass" = dlopen; then + if test -z "$libdir"; then + $echo "$modename: cannot -dlopen a convenience library: \`$lib'" 1>&2 + exit $EXIT_FAILURE + fi + if test -z "$dlname" || + test "$dlopen_support" != yes || + test "$build_libtool_libs" = no; then + # If there is no dlname, no dlopen support or we're linking + # statically, we need to preload. We also need to preload any + # dependent libraries so libltdl's deplib preloader doesn't + # bomb out in the load deplibs phase. + dlprefiles="$dlprefiles $lib $dependency_libs" + else + newdlfiles="$newdlfiles $lib" + fi + continue + fi # $pass = dlopen + + # We need an absolute path. + case $ladir in + [\\/]* | [A-Za-z]:[\\/]*) abs_ladir="$ladir" ;; + *) + abs_ladir=`cd "$ladir" && pwd` + if test -z "$abs_ladir"; then + $echo "$modename: warning: cannot determine absolute directory name of \`$ladir'" 1>&2 + $echo "$modename: passing it literally to the linker, although it might fail" 1>&2 + abs_ladir="$ladir" + fi + ;; + esac + laname=`$echo "X$lib" | $Xsed -e 's%^.*/%%'` + + # Find the relevant object directory and library name. + if test "X$installed" = Xyes; then + if test ! -f "$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then + $echo "$modename: warning: library \`$lib' was moved." 1>&2 + dir="$ladir" + absdir="$abs_ladir" + libdir="$abs_ladir" + else + dir="$libdir" + absdir="$libdir" + fi + test "X$hardcode_automatic" = Xyes && avoidtemprpath=yes + else + if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then + dir="$ladir" + absdir="$abs_ladir" + # Remove this search path later + notinst_path="$notinst_path $abs_ladir" + else + dir="$ladir/$objdir" + absdir="$abs_ladir/$objdir" + # Remove this search path later + notinst_path="$notinst_path $abs_ladir" + fi + fi # $installed = yes + name=`$echo "X$laname" | $Xsed -e 's/\.la$//' -e 's/^lib//'` + + # This library was specified with -dlpreopen. + if test "$pass" = dlpreopen; then + if test -z "$libdir"; then + $echo "$modename: cannot -dlpreopen a convenience library: \`$lib'" 1>&2 + exit $EXIT_FAILURE + fi + # Prefer using a static library (so that no silly _DYNAMIC symbols + # are required to link). + if test -n "$old_library"; then + newdlprefiles="$newdlprefiles $dir/$old_library" + # Otherwise, use the dlname, so that lt_dlopen finds it. + elif test -n "$dlname"; then + newdlprefiles="$newdlprefiles $dir/$dlname" + else + newdlprefiles="$newdlprefiles $dir/$linklib" + fi + fi # $pass = dlpreopen + + if test -z "$libdir"; then + # Link the convenience library + if test "$linkmode" = lib; then + deplibs="$dir/$old_library $deplibs" + elif test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$dir/$old_library $compile_deplibs" + finalize_deplibs="$dir/$old_library $finalize_deplibs" + else + deplibs="$lib $deplibs" # used for prog,scan pass + fi + continue + fi + + + if test "$linkmode" = prog && test "$pass" != link; then + newlib_search_path="$newlib_search_path $ladir" + deplibs="$lib $deplibs" + + linkalldeplibs=no + if test "$link_all_deplibs" != no || test -z "$library_names" || + test "$build_libtool_libs" = no; then + linkalldeplibs=yes + fi + + tmp_libs= + for deplib in $dependency_libs; do + case $deplib in + -L*) newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'`;; ### testsuite: skip nested quoting test + esac + # Need to link against all dependency_libs? + if test "$linkalldeplibs" = yes; then + deplibs="$deplib $deplibs" + else + # Need to hardcode shared library paths + # or/and link against static libraries + newdependency_libs="$deplib $newdependency_libs" + fi + if test "X$duplicate_deps" = "Xyes" ; then + case "$tmp_libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + fi + tmp_libs="$tmp_libs $deplib" + done # for deplib + continue + fi # $linkmode = prog... + + if test "$linkmode,$pass" = "prog,link"; then + if test -n "$library_names" && + { { test "$prefer_static_libs" = no || + test "$prefer_static_libs,$installed" = "built,yes"; } || + test -z "$old_library"; }; then + # We need to hardcode the library path + if test -n "$shlibpath_var" && test -z "$avoidtemprpath" ; then + # Make sure the rpath contains only unique directories. + case "$temp_rpath " in + *" $dir "*) ;; + *" $absdir "*) ;; + *) temp_rpath="$temp_rpath $absdir" ;; + esac + fi + + # Hardcode the library path. + # Skip directories that are in the system default run-time + # search path. + case " $sys_lib_dlsearch_path " in + *" $absdir "*) ;; + *) + case "$compile_rpath " in + *" $absdir "*) ;; + *) compile_rpath="$compile_rpath $absdir" + esac + ;; + esac + case " $sys_lib_dlsearch_path " in + *" $libdir "*) ;; + *) + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" + esac + ;; + esac + fi # $linkmode,$pass = prog,link... + + if test "$alldeplibs" = yes && + { test "$deplibs_check_method" = pass_all || + { test "$build_libtool_libs" = yes && + test -n "$library_names"; }; }; then + # We only need to search for static libraries + continue + fi + fi + + link_static=no # Whether the deplib will be linked statically + use_static_libs=$prefer_static_libs + if test "$use_static_libs" = built && test "$installed" = yes ; then + use_static_libs=no + fi + if test -n "$library_names" && + { test "$use_static_libs" = no || test -z "$old_library"; }; then + if test "$installed" = no; then + notinst_deplibs="$notinst_deplibs $lib" + need_relink=yes + fi + # This is a shared library + + # Warn about portability, can't link against -module's on + # some systems (darwin) + if test "$shouldnotlink" = yes && test "$pass" = link ; then + $echo + if test "$linkmode" = prog; then + $echo "*** Warning: Linking the executable $output against the loadable module" + else + $echo "*** Warning: Linking the shared library $output against the loadable module" + fi + $echo "*** $linklib is not portable!" + fi + if test "$linkmode" = lib && + test "$hardcode_into_libs" = yes; then + # Hardcode the library path. + # Skip directories that are in the system default run-time + # search path. + case " $sys_lib_dlsearch_path " in + *" $absdir "*) ;; + *) + case "$compile_rpath " in + *" $absdir "*) ;; + *) compile_rpath="$compile_rpath $absdir" + esac + ;; + esac + case " $sys_lib_dlsearch_path " in + *" $libdir "*) ;; + *) + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" + esac + ;; + esac + fi + + if test -n "$old_archive_from_expsyms_cmds"; then + # figure out the soname + set dummy $library_names + realname="$2" + shift; shift + libname=`eval \\$echo \"$libname_spec\"` + # use dlname if we got it. it's perfectly good, no? + if test -n "$dlname"; then + soname="$dlname" + elif test -n "$soname_spec"; then + # bleh windows + case $host in + *cygwin* | mingw*) + major=`expr $current - $age` + versuffix="-$major" + ;; + esac + eval soname=\"$soname_spec\" + else + soname="$realname" + fi + + # Make a new name for the extract_expsyms_cmds to use + soroot="$soname" + soname=`$echo $soroot | ${SED} -e 's/^.*\///'` + newlib="libimp-`$echo $soname | ${SED} 's/^lib//;s/\.dll$//'`.a" + + # If the library has no export list, then create one now + if test -f "$output_objdir/$soname-def"; then : + else + $show "extracting exported symbol list from \`$soname'" + save_ifs="$IFS"; IFS='~' + cmds=$extract_expsyms_cmds + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + fi + + # Create $newlib + if test -f "$output_objdir/$newlib"; then :; else + $show "generating import library for \`$soname'" + save_ifs="$IFS"; IFS='~' + cmds=$old_archive_from_expsyms_cmds + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + fi + # make sure the library variables are pointing to the new library + dir=$output_objdir + linklib=$newlib + fi # test -n "$old_archive_from_expsyms_cmds" + + if test "$linkmode" = prog || test "$mode" != relink; then + add_shlibpath= + add_dir= + add= + lib_linked=yes + case $hardcode_action in + immediate | unsupported) + if test "$hardcode_direct" = no; then + add="$dir/$linklib" + case $host in + *-*-sco3.2v5.0.[024]*) add_dir="-L$dir" ;; + *-*-sysv4*uw2*) add_dir="-L$dir" ;; + *-*-sysv5OpenUNIX* | *-*-sysv5UnixWare7.[01].[10]* | \ + *-*-unixware7*) add_dir="-L$dir" ;; + *-*-darwin* ) + # if the lib is a module then we can not link against + # it, someone is ignoring the new warnings I added + if /usr/bin/file -L $add 2> /dev/null | + $EGREP ": [^:]* bundle" >/dev/null ; then + $echo "** Warning, lib $linklib is a module, not a shared library" + if test -z "$old_library" ; then + $echo + $echo "** And there doesn't seem to be a static archive available" + $echo "** The link will probably fail, sorry" + else + add="$dir/$old_library" + fi + fi + esac + elif test "$hardcode_minus_L" = no; then + case $host in + *-*-sunos*) add_shlibpath="$dir" ;; + esac + add_dir="-L$dir" + add="-l$name" + elif test "$hardcode_shlibpath_var" = no; then + add_shlibpath="$dir" + add="-l$name" + else + lib_linked=no + fi + ;; + relink) + if test "$hardcode_direct" = yes; then + add="$dir/$linklib" + elif test "$hardcode_minus_L" = yes; then + add_dir="-L$dir" + # Try looking first in the location we're being installed to. + if test -n "$inst_prefix_dir"; then + case $libdir in + [\\/]*) + add_dir="$add_dir -L$inst_prefix_dir$libdir" + ;; + esac + fi + add="-l$name" + elif test "$hardcode_shlibpath_var" = yes; then + add_shlibpath="$dir" + add="-l$name" + else + lib_linked=no + fi + ;; + *) lib_linked=no ;; + esac + + if test "$lib_linked" != yes; then + $echo "$modename: configuration error: unsupported hardcode properties" + exit $EXIT_FAILURE + fi + + if test -n "$add_shlibpath"; then + case :$compile_shlibpath: in + *":$add_shlibpath:"*) ;; + *) compile_shlibpath="$compile_shlibpath$add_shlibpath:" ;; + esac + fi + if test "$linkmode" = prog; then + test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs" + test -n "$add" && compile_deplibs="$add $compile_deplibs" + else + test -n "$add_dir" && deplibs="$add_dir $deplibs" + test -n "$add" && deplibs="$add $deplibs" + if test "$hardcode_direct" != yes && \ + test "$hardcode_minus_L" != yes && \ + test "$hardcode_shlibpath_var" = yes; then + case :$finalize_shlibpath: in + *":$libdir:"*) ;; + *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;; + esac + fi + fi + fi + + if test "$linkmode" = prog || test "$mode" = relink; then + add_shlibpath= + add_dir= + add= + # Finalize command for both is simple: just hardcode it. + if test "$hardcode_direct" = yes; then + add="$libdir/$linklib" + elif test "$hardcode_minus_L" = yes; then + add_dir="-L$libdir" + add="-l$name" + elif test "$hardcode_shlibpath_var" = yes; then + case :$finalize_shlibpath: in + *":$libdir:"*) ;; + *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;; + esac + add="-l$name" + elif test "$hardcode_automatic" = yes; then + if test -n "$inst_prefix_dir" && + test -f "$inst_prefix_dir$libdir/$linklib" ; then + add="$inst_prefix_dir$libdir/$linklib" + else + add="$libdir/$linklib" + fi + else + # We cannot seem to hardcode it, guess we'll fake it. + add_dir="-L$libdir" + # Try looking first in the location we're being installed to. + if test -n "$inst_prefix_dir"; then + case $libdir in + [\\/]*) + add_dir="$add_dir -L$inst_prefix_dir$libdir" + ;; + esac + fi + add="-l$name" + fi + + if test "$linkmode" = prog; then + test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs" + test -n "$add" && finalize_deplibs="$add $finalize_deplibs" + else + test -n "$add_dir" && deplibs="$add_dir $deplibs" + test -n "$add" && deplibs="$add $deplibs" + fi + fi + elif test "$linkmode" = prog; then + # Here we assume that one of hardcode_direct or hardcode_minus_L + # is not unsupported. This is valid on all known static and + # shared platforms. + if test "$hardcode_direct" != unsupported; then + test -n "$old_library" && linklib="$old_library" + compile_deplibs="$dir/$linklib $compile_deplibs" + finalize_deplibs="$dir/$linklib $finalize_deplibs" + else + compile_deplibs="-l$name -L$dir $compile_deplibs" + finalize_deplibs="-l$name -L$dir $finalize_deplibs" + fi + elif test "$build_libtool_libs" = yes; then + # Not a shared library + if test "$deplibs_check_method" != pass_all; then + # We're trying link a shared library against a static one + # but the system doesn't support it. + + # Just print a warning and add the library to dependency_libs so + # that the program can be linked against the static library. + $echo + $echo "*** Warning: This system can not link to static lib archive $lib." + $echo "*** I have the capability to make that library automatically link in when" + $echo "*** you link to this library. But I can only do this if you have a" + $echo "*** shared version of the library, which you do not appear to have." + if test "$module" = yes; then + $echo "*** But as you try to build a module library, libtool will still create " + $echo "*** a static module, that should work as long as the dlopening application" + $echo "*** is linked with the -dlopen flag to resolve symbols at runtime." + if test -z "$global_symbol_pipe"; then + $echo + $echo "*** However, this would only work if libtool was able to extract symbol" + $echo "*** lists from a program, using \`nm' or equivalent, but libtool could" + $echo "*** not find such a program. So, this module is probably useless." + $echo "*** \`nm' from GNU binutils and a full rebuild may help." + fi + if test "$build_old_libs" = no; then + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + fi + else + deplibs="$dir/$old_library $deplibs" + link_static=yes + fi + fi # link shared/static library? + + if test "$linkmode" = lib; then + if test -n "$dependency_libs" && + { test "$hardcode_into_libs" != yes || + test "$build_old_libs" = yes || + test "$link_static" = yes; }; then + # Extract -R from dependency_libs + temp_deplibs= + for libdir in $dependency_libs; do + case $libdir in + -R*) temp_xrpath=`$echo "X$libdir" | $Xsed -e 's/^-R//'` + case " $xrpath " in + *" $temp_xrpath "*) ;; + *) xrpath="$xrpath $temp_xrpath";; + esac;; + *) temp_deplibs="$temp_deplibs $libdir";; + esac + done + dependency_libs="$temp_deplibs" + fi + + newlib_search_path="$newlib_search_path $absdir" + # Link against this library + test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs" + # ... and its dependency_libs + tmp_libs= + for deplib in $dependency_libs; do + newdependency_libs="$deplib $newdependency_libs" + if test "X$duplicate_deps" = "Xyes" ; then + case "$tmp_libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + fi + tmp_libs="$tmp_libs $deplib" + done + + if test "$link_all_deplibs" != no; then + # Add the search paths of all dependency libraries + for deplib in $dependency_libs; do + case $deplib in + -L*) path="$deplib" ;; + *.la) + dir=`$echo "X$deplib" | $Xsed -e 's%/[^/]*$%%'` + test "X$dir" = "X$deplib" && dir="." + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) absdir="$dir" ;; + *) + absdir=`cd "$dir" && pwd` + if test -z "$absdir"; then + $echo "$modename: warning: cannot determine absolute directory name of \`$dir'" 1>&2 + absdir="$dir" + fi + ;; + esac + if grep "^installed=no" $deplib > /dev/null; then + path="$absdir/$objdir" + else + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` + if test -z "$libdir"; then + $echo "$modename: \`$deplib' is not a valid libtool archive" 1>&2 + exit $EXIT_FAILURE + fi + if test "$absdir" != "$libdir"; then + $echo "$modename: warning: \`$deplib' seems to be moved" 1>&2 + fi + path="$absdir" + fi + depdepl= + case $host in + *-*-darwin*) + # we do not want to link against static libs, + # but need to link against shared + eval deplibrary_names=`${SED} -n -e 's/^library_names=\(.*\)$/\1/p' $deplib` + eval deplibdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` + if test -n "$deplibrary_names" ; then + for tmp in $deplibrary_names ; do + depdepl=$tmp + done + if test -f "$deplibdir/$depdepl" ; then + depdepl="$deplibdir/$depdepl" + elif test -f "$path/$depdepl" ; then + depdepl="$path/$depdepl" + else + # Can't find it, oh well... + depdepl= + fi + # do not add paths which are already there + case " $newlib_search_path " in + *" $path "*) ;; + *) newlib_search_path="$newlib_search_path $path";; + esac + fi + path="" + ;; + *) + path="-L$path" + ;; + esac + ;; + -l*) + case $host in + *-*-darwin*) + # Again, we only want to link against shared libraries + eval tmp_libs=`$echo "X$deplib" | $Xsed -e "s,^\-l,,"` + for tmp in $newlib_search_path ; do + if test -f "$tmp/lib$tmp_libs.dylib" ; then + eval depdepl="$tmp/lib$tmp_libs.dylib" + break + fi + done + path="" + ;; + *) continue ;; + esac + ;; + *) continue ;; + esac + case " $deplibs " in + *" $path "*) ;; + *) deplibs="$path $deplibs" ;; + esac + case " $deplibs " in + *" $depdepl "*) ;; + *) deplibs="$depdepl $deplibs" ;; + esac + done + fi # link_all_deplibs != no + fi # linkmode = lib + done # for deplib in $libs + dependency_libs="$newdependency_libs" + if test "$pass" = dlpreopen; then + # Link the dlpreopened libraries before other libraries + for deplib in $save_deplibs; do + deplibs="$deplib $deplibs" + done + fi + if test "$pass" != dlopen; then + if test "$pass" != conv; then + # Make sure lib_search_path contains only unique directories. + lib_search_path= + for dir in $newlib_search_path; do + case "$lib_search_path " in + *" $dir "*) ;; + *) lib_search_path="$lib_search_path $dir" ;; + esac + done + newlib_search_path= + fi + + if test "$linkmode,$pass" != "prog,link"; then + vars="deplibs" + else + vars="compile_deplibs finalize_deplibs" + fi + for var in $vars dependency_libs; do + # Add libraries to $var in reverse order + eval tmp_libs=\"\$$var\" + new_libs= + for deplib in $tmp_libs; do + # FIXME: Pedantically, this is the right thing to do, so + # that some nasty dependency loop isn't accidentally + # broken: + #new_libs="$deplib $new_libs" + # Pragmatically, this seems to cause very few problems in + # practice: + case $deplib in + -L*) new_libs="$deplib $new_libs" ;; + -R*) ;; + *) + # And here is the reason: when a library appears more + # than once as an explicit dependence of a library, or + # is implicitly linked in more than once by the + # compiler, it is considered special, and multiple + # occurrences thereof are not removed. Compare this + # with having the same library being listed as a + # dependency of multiple other libraries: in this case, + # we know (pedantically, we assume) the library does not + # need to be listed more than once, so we keep only the + # last copy. This is not always right, but it is rare + # enough that we require users that really mean to play + # such unportable linking tricks to link the library + # using -Wl,-lname, so that libtool does not consider it + # for duplicate removal. + case " $specialdeplibs " in + *" $deplib "*) new_libs="$deplib $new_libs" ;; + *) + case " $new_libs " in + *" $deplib "*) ;; + *) new_libs="$deplib $new_libs" ;; + esac + ;; + esac + ;; + esac + done + tmp_libs= + for deplib in $new_libs; do + case $deplib in + -L*) + case " $tmp_libs " in + *" $deplib "*) ;; + *) tmp_libs="$tmp_libs $deplib" ;; + esac + ;; + *) tmp_libs="$tmp_libs $deplib" ;; + esac + done + eval $var=\"$tmp_libs\" + done # for var + fi + # Last step: remove runtime libs from dependency_libs + # (they stay in deplibs) + tmp_libs= + for i in $dependency_libs ; do + case " $predeps $postdeps $compiler_lib_search_path " in + *" $i "*) + i="" + ;; + esac + if test -n "$i" ; then + tmp_libs="$tmp_libs $i" + fi + done + dependency_libs=$tmp_libs + done # for pass + if test "$linkmode" = prog; then + dlfiles="$newdlfiles" + dlprefiles="$newdlprefiles" + fi + + case $linkmode in + oldlib) + case " $deplibs" in + *\ -l* | *\ -L*) + $echo "$modename: warning: \`-l' and \`-L' are ignored for archives" 1>&2 ;; + esac + + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + $echo "$modename: warning: \`-dlopen' is ignored for archives" 1>&2 + fi + + if test -n "$rpath"; then + $echo "$modename: warning: \`-rpath' is ignored for archives" 1>&2 + fi + + if test -n "$xrpath"; then + $echo "$modename: warning: \`-R' is ignored for archives" 1>&2 + fi + + if test -n "$vinfo"; then + $echo "$modename: warning: \`-version-info/-version-number' is ignored for archives" 1>&2 + fi + + if test -n "$release"; then + $echo "$modename: warning: \`-release' is ignored for archives" 1>&2 + fi + + if test -n "$export_symbols" || test -n "$export_symbols_regex"; then + $echo "$modename: warning: \`-export-symbols' is ignored for archives" 1>&2 + fi + + # Now set the variables for building old libraries. + build_libtool_libs=no + oldlibs="$output" + objs="$objs$old_deplibs" + ;; + + lib) + # Make sure we only generate libraries of the form `libNAME.la'. + case $outputname in + lib*) + name=`$echo "X$outputname" | $Xsed -e 's/\.la$//' -e 's/^lib//'` + eval shared_ext=\"$shrext_cmds\" + eval libname=\"$libname_spec\" + ;; + *) + if test "$module" = no; then + $echo "$modename: libtool library \`$output' must begin with \`lib'" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + if test "$need_lib_prefix" != no; then + # Add the "lib" prefix for modules if required + name=`$echo "X$outputname" | $Xsed -e 's/\.la$//'` + eval shared_ext=\"$shrext_cmds\" + eval libname=\"$libname_spec\" + else + libname=`$echo "X$outputname" | $Xsed -e 's/\.la$//'` + fi + ;; + esac + + if test -n "$objs"; then + if test "$deplibs_check_method" != pass_all; then + $echo "$modename: cannot build libtool library \`$output' from non-libtool objects on this host:$objs" 2>&1 + exit $EXIT_FAILURE + else + $echo + $echo "*** Warning: Linking the shared library $output against the non-libtool" + $echo "*** objects $objs is not portable!" + libobjs="$libobjs $objs" + fi + fi + + if test "$dlself" != no; then + $echo "$modename: warning: \`-dlopen self' is ignored for libtool libraries" 1>&2 + fi + + set dummy $rpath + if test "$#" -gt 2; then + $echo "$modename: warning: ignoring multiple \`-rpath's for a libtool library" 1>&2 + fi + install_libdir="$2" + + oldlibs= + if test -z "$rpath"; then + if test "$build_libtool_libs" = yes; then + # Building a libtool convenience library. + # Some compilers have problems with a `.al' extension so + # convenience libraries should have the same extension an + # archive normally would. + oldlibs="$output_objdir/$libname.$libext $oldlibs" + build_libtool_libs=convenience + build_old_libs=yes + fi + + if test -n "$vinfo"; then + $echo "$modename: warning: \`-version-info/-version-number' is ignored for convenience libraries" 1>&2 + fi + + if test -n "$release"; then + $echo "$modename: warning: \`-release' is ignored for convenience libraries" 1>&2 + fi + else + + # Parse the version information argument. + save_ifs="$IFS"; IFS=':' + set dummy $vinfo 0 0 0 + IFS="$save_ifs" + + if test -n "$8"; then + $echo "$modename: too many parameters to \`-version-info'" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + # convert absolute version numbers to libtool ages + # this retains compatibility with .la files and attempts + # to make the code below a bit more comprehensible + + case $vinfo_number in + yes) + number_major="$2" + number_minor="$3" + number_revision="$4" + # + # There are really only two kinds -- those that + # use the current revision as the major version + # and those that subtract age and use age as + # a minor version. But, then there is irix + # which has an extra 1 added just for fun + # + case $version_type in + darwin|linux|osf|windows|none) + current=`expr $number_major + $number_minor` + age="$number_minor" + revision="$number_revision" + ;; + freebsd-aout|freebsd-elf|sunos) + current="$number_major" + revision="$number_minor" + age="0" + ;; + irix|nonstopux) + current=`expr $number_major + $number_minor` + age="$number_minor" + revision="$number_minor" + lt_irix_increment=no + ;; + esac + ;; + no) + current="$2" + revision="$3" + age="$4" + ;; + esac + + # Check that each of the things are valid numbers. + case $current in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + $echo "$modename: CURRENT \`$current' must be a nonnegative integer" 1>&2 + $echo "$modename: \`$vinfo' is not valid version information" 1>&2 + exit $EXIT_FAILURE + ;; + esac + + case $revision in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + $echo "$modename: REVISION \`$revision' must be a nonnegative integer" 1>&2 + $echo "$modename: \`$vinfo' is not valid version information" 1>&2 + exit $EXIT_FAILURE + ;; + esac + + case $age in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + $echo "$modename: AGE \`$age' must be a nonnegative integer" 1>&2 + $echo "$modename: \`$vinfo' is not valid version information" 1>&2 + exit $EXIT_FAILURE + ;; + esac + + if test "$age" -gt "$current"; then + $echo "$modename: AGE \`$age' is greater than the current interface number \`$current'" 1>&2 + $echo "$modename: \`$vinfo' is not valid version information" 1>&2 + exit $EXIT_FAILURE + fi + + # Calculate the version variables. + major= + versuffix= + verstring= + case $version_type in + none) ;; + + darwin) + # Like Linux, but with the current version available in + # verstring for coding it into the library header + major=.`expr $current - $age` + versuffix="$major.$age.$revision" + # Darwin ld doesn't like 0 for these options... + minor_current=`expr $current + 1` + xlcverstring="${wl}-compatibility_version ${wl}$minor_current ${wl}-current_version ${wl}$minor_current.$revision" + verstring="-compatibility_version $minor_current -current_version $minor_current.$revision" + ;; + + freebsd-aout) + major=".$current" + versuffix=".$current.$revision"; + ;; + + freebsd-elf) + major=".$current" + versuffix=".$current"; + ;; + + irix | nonstopux) + if test "X$lt_irix_increment" = "Xno"; then + major=`expr $current - $age` + else + major=`expr $current - $age + 1` + fi + case $version_type in + nonstopux) verstring_prefix=nonstopux ;; + *) verstring_prefix=sgi ;; + esac + verstring="$verstring_prefix$major.$revision" + + # Add in all the interfaces that we are compatible with. + loop=$revision + while test "$loop" -ne 0; do + iface=`expr $revision - $loop` + loop=`expr $loop - 1` + verstring="$verstring_prefix$major.$iface:$verstring" + done + + # Before this point, $major must not contain `.'. + major=.$major + versuffix="$major.$revision" + ;; + + linux) + major=.`expr $current - $age` + versuffix="$major.$age.$revision" + ;; + + osf) + major=.`expr $current - $age` + versuffix=".$current.$age.$revision" + verstring="$current.$age.$revision" + + # Add in all the interfaces that we are compatible with. + loop=$age + while test "$loop" -ne 0; do + iface=`expr $current - $loop` + loop=`expr $loop - 1` + verstring="$verstring:${iface}.0" + done + + # Make executables depend on our current version. + verstring="$verstring:${current}.0" + ;; + + sunos) + major=".$current" + versuffix=".$current.$revision" + ;; + + windows) + # Use '-' rather than '.', since we only want one + # extension on DOS 8.3 filesystems. + major=`expr $current - $age` + versuffix="-$major" + ;; + + *) + $echo "$modename: unknown library version type \`$version_type'" 1>&2 + $echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2 + exit $EXIT_FAILURE + ;; + esac + + # Clear the version info if we defaulted, and they specified a release. + if test -z "$vinfo" && test -n "$release"; then + major= + case $version_type in + darwin) + # we can't check for "0.0" in archive_cmds due to quoting + # problems, so we reset it completely + verstring= + ;; + *) + verstring="0.0" + ;; + esac + if test "$need_version" = no; then + versuffix= + else + versuffix=".0.0" + fi + fi + + # Remove version info from name if versioning should be avoided + if test "$avoid_version" = yes && test "$need_version" = no; then + major= + versuffix= + verstring="" + fi + + # Check to see if the archive will have undefined symbols. + if test "$allow_undefined" = yes; then + if test "$allow_undefined_flag" = unsupported; then + $echo "$modename: warning: undefined symbols not allowed in $host shared libraries" 1>&2 + build_libtool_libs=no + build_old_libs=yes + fi + else + # Don't allow undefined symbols. + allow_undefined_flag="$no_undefined_flag" + fi + fi + + if test "$mode" != relink; then + # Remove our outputs, but don't remove object files since they + # may have been created when compiling PIC objects. + removelist= + tempremovelist=`$echo "$output_objdir/*"` + for p in $tempremovelist; do + case $p in + *.$objext) + ;; + $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/${libname}${release}.*) + if test "X$precious_files_regex" != "X"; then + if echo $p | $EGREP -e "$precious_files_regex" >/dev/null 2>&1 + then + continue + fi + fi + removelist="$removelist $p" + ;; + *) ;; + esac + done + if test -n "$removelist"; then + $show "${rm}r $removelist" + $run ${rm}r $removelist + fi + fi + + # Now set the variables for building old libraries. + if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then + oldlibs="$oldlibs $output_objdir/$libname.$libext" + + # Transform .lo files to .o files. + oldobjs="$objs "`$echo "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}'$/d' -e "$lo2o" | $NL2SP` + fi + + # Eliminate all temporary directories. + #for path in $notinst_path; do + # lib_search_path=`$echo "$lib_search_path " | ${SED} -e "s% $path % %g"` + # deplibs=`$echo "$deplibs " | ${SED} -e "s% -L$path % %g"` + # dependency_libs=`$echo "$dependency_libs " | ${SED} -e "s% -L$path % %g"` + #done + + if test -n "$xrpath"; then + # If the user specified any rpath flags, then add them. + temp_xrpath= + for libdir in $xrpath; do + temp_xrpath="$temp_xrpath -R$libdir" + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" ;; + esac + done + if test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes; then + dependency_libs="$temp_xrpath $dependency_libs" + fi + fi + + # Make sure dlfiles contains only unique files that won't be dlpreopened + old_dlfiles="$dlfiles" + dlfiles= + for lib in $old_dlfiles; do + case " $dlprefiles $dlfiles " in + *" $lib "*) ;; + *) dlfiles="$dlfiles $lib" ;; + esac + done + + # Make sure dlprefiles contains only unique files + old_dlprefiles="$dlprefiles" + dlprefiles= + for lib in $old_dlprefiles; do + case "$dlprefiles " in + *" $lib "*) ;; + *) dlprefiles="$dlprefiles $lib" ;; + esac + done + + if test "$build_libtool_libs" = yes; then + if test -n "$rpath"; then + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos*) + # these systems don't actually have a c library (as such)! + ;; + *-*-rhapsody* | *-*-darwin1.[012]) + # Rhapsody C library is in the System framework + deplibs="$deplibs -framework System" + ;; + *-*-netbsd*) + # Don't link with libc until the a.out ld.so is fixed. + ;; + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) + # Do not include libc due to us having libc/libc_r. + ;; + *-*-sco3.2v5* | *-*-sco5v6*) + # Causes problems with __ctype + ;; + *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) + # Compiler inserts libc in the correct place for threads to work + ;; + *) + # Add libc to deplibs on all other systems if necessary. + if test "$build_libtool_need_lc" = "yes"; then + deplibs="$deplibs -lc" + fi + ;; + esac + fi + + # Transform deplibs into only deplibs that can be linked in shared. + name_save=$name + libname_save=$libname + release_save=$release + versuffix_save=$versuffix + major_save=$major + # I'm not sure if I'm treating the release correctly. I think + # release should show up in the -l (ie -lgmp5) so we don't want to + # add it in twice. Is that correct? + release="" + versuffix="" + major="" + newdeplibs= + droppeddeps=no + case $deplibs_check_method in + pass_all) + # Don't check for shared/static. Everything works. + # This might be a little naive. We might want to check + # whether the library exists or not. But this is on + # osf3 & osf4 and I'm not really sure... Just + # implementing what was already the behavior. + newdeplibs=$deplibs + ;; + test_compile) + # This code stresses the "libraries are programs" paradigm to its + # limits. Maybe even breaks it. We compile a program, linking it + # against the deplibs as a proxy for the library. Then we can check + # whether they linked in statically or dynamically with ldd. + $rm conftest.c + cat > conftest.c </dev/null` + for potent_lib in $potential_libs; do + # Follow soft links. + if ls -lLd "$potent_lib" 2>/dev/null \ + | grep " -> " >/dev/null; then + continue + fi + # The statement above tries to avoid entering an + # endless loop below, in case of cyclic links. + # We might still enter an endless loop, since a link + # loop can be closed while we follow links, + # but so what? + potlib="$potent_lib" + while test -h "$potlib" 2>/dev/null; do + potliblink=`ls -ld $potlib | ${SED} 's/.* -> //'` + case $potliblink in + [\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";; + *) potlib=`$echo "X$potlib" | $Xsed -e 's,[^/]*$,,'`"$potliblink";; + esac + done + if eval $file_magic_cmd \"\$potlib\" 2>/dev/null \ + | ${SED} 10q \ + | $EGREP "$file_magic_regex" > /dev/null; then + newdeplibs="$newdeplibs $a_deplib" + a_deplib="" + break 2 + fi + done + done + fi + if test -n "$a_deplib" ; then + droppeddeps=yes + $echo + $echo "*** Warning: linker path does not have real file for library $a_deplib." + $echo "*** I have the capability to make that library automatically link in when" + $echo "*** you link to this library. But I can only do this if you have a" + $echo "*** shared version of the library, which you do not appear to have" + $echo "*** because I did check the linker path looking for a file starting" + if test -z "$potlib" ; then + $echo "*** with $libname but no candidates were found. (...for file magic test)" + else + $echo "*** with $libname and none of the candidates passed a file format test" + $echo "*** using a file magic. Last file checked: $potlib" + fi + fi + else + # Add a -L argument. + newdeplibs="$newdeplibs $a_deplib" + fi + done # Gone through all deplibs. + ;; + match_pattern*) + set dummy $deplibs_check_method + match_pattern_regex=`expr "$deplibs_check_method" : "$2 \(.*\)"` + for a_deplib in $deplibs; do + name=`expr $a_deplib : '-l\(.*\)'` + # If $name is empty we are operating on a -L argument. + if test -n "$name" && test "$name" != "0"; then + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + case " $predeps $postdeps " in + *" $a_deplib "*) + newdeplibs="$newdeplibs $a_deplib" + a_deplib="" + ;; + esac + fi + if test -n "$a_deplib" ; then + libname=`eval \\$echo \"$libname_spec\"` + for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do + potential_libs=`ls $i/$libname[.-]* 2>/dev/null` + for potent_lib in $potential_libs; do + potlib="$potent_lib" # see symlink-check above in file_magic test + if eval $echo \"$potent_lib\" 2>/dev/null \ + | ${SED} 10q \ + | $EGREP "$match_pattern_regex" > /dev/null; then + newdeplibs="$newdeplibs $a_deplib" + a_deplib="" + break 2 + fi + done + done + fi + if test -n "$a_deplib" ; then + droppeddeps=yes + $echo + $echo "*** Warning: linker path does not have real file for library $a_deplib." + $echo "*** I have the capability to make that library automatically link in when" + $echo "*** you link to this library. But I can only do this if you have a" + $echo "*** shared version of the library, which you do not appear to have" + $echo "*** because I did check the linker path looking for a file starting" + if test -z "$potlib" ; then + $echo "*** with $libname but no candidates were found. (...for regex pattern test)" + else + $echo "*** with $libname and none of the candidates passed a file format test" + $echo "*** using a regex pattern. Last file checked: $potlib" + fi + fi + else + # Add a -L argument. + newdeplibs="$newdeplibs $a_deplib" + fi + done # Gone through all deplibs. + ;; + none | unknown | *) + newdeplibs="" + tmp_deplibs=`$echo "X $deplibs" | $Xsed -e 's/ -lc$//' \ + -e 's/ -[LR][^ ]*//g'` + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + for i in $predeps $postdeps ; do + # can't use Xsed below, because $i might contain '/' + tmp_deplibs=`$echo "X $tmp_deplibs" | ${SED} -e "1s,^X,," -e "s,$i,,"` + done + fi + if $echo "X $tmp_deplibs" | $Xsed -e 's/[ ]//g' \ + | grep . >/dev/null; then + $echo + if test "X$deplibs_check_method" = "Xnone"; then + $echo "*** Warning: inter-library dependencies are not supported in this platform." + else + $echo "*** Warning: inter-library dependencies are not known to be supported." + fi + $echo "*** All declared inter-library dependencies are being dropped." + droppeddeps=yes + fi + ;; + esac + versuffix=$versuffix_save + major=$major_save + release=$release_save + libname=$libname_save + name=$name_save + + case $host in + *-*-rhapsody* | *-*-darwin1.[012]) + # On Rhapsody replace the C library is the System framework + newdeplibs=`$echo "X $newdeplibs" | $Xsed -e 's/ -lc / -framework System /'` + ;; + esac + + if test "$droppeddeps" = yes; then + if test "$module" = yes; then + $echo + $echo "*** Warning: libtool could not satisfy all declared inter-library" + $echo "*** dependencies of module $libname. Therefore, libtool will create" + $echo "*** a static module, that should work as long as the dlopening" + $echo "*** application is linked with the -dlopen flag." + if test -z "$global_symbol_pipe"; then + $echo + $echo "*** However, this would only work if libtool was able to extract symbol" + $echo "*** lists from a program, using \`nm' or equivalent, but libtool could" + $echo "*** not find such a program. So, this module is probably useless." + $echo "*** \`nm' from GNU binutils and a full rebuild may help." + fi + if test "$build_old_libs" = no; then + oldlibs="$output_objdir/$libname.$libext" + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + else + $echo "*** The inter-library dependencies that have been dropped here will be" + $echo "*** automatically added whenever a program is linked with this library" + $echo "*** or is declared to -dlopen it." + + if test "$allow_undefined" = no; then + $echo + $echo "*** Since this library must not contain undefined symbols," + $echo "*** because either the platform does not support them or" + $echo "*** it was explicitly requested with -no-undefined," + $echo "*** libtool will only create a static version of it." + if test "$build_old_libs" = no; then + oldlibs="$output_objdir/$libname.$libext" + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + fi + fi + fi + # Done checking deplibs! + deplibs=$newdeplibs + fi + + + # move library search paths that coincide with paths to not yet + # installed libraries to the beginning of the library search list + new_libs= + for path in $notinst_path; do + case " $new_libs " in + *" -L$path/$objdir "*) ;; + *) + case " $deplibs " in + *" -L$path/$objdir "*) + new_libs="$new_libs -L$path/$objdir" ;; + esac + ;; + esac + done + for deplib in $deplibs; do + case $deplib in + -L*) + case " $new_libs " in + *" $deplib "*) ;; + *) new_libs="$new_libs $deplib" ;; + esac + ;; + *) new_libs="$new_libs $deplib" ;; + esac + done + deplibs="$new_libs" + + + # All the library-specific variables (install_libdir is set above). + library_names= + old_library= + dlname= + + # Test again, we may have decided not to build it any more + if test "$build_libtool_libs" = yes; then + if test "$hardcode_into_libs" = yes; then + # Hardcode the library paths + hardcode_libdirs= + dep_rpath= + rpath="$finalize_rpath" + test "$mode" != relink && rpath="$compile_rpath$rpath" + for libdir in $rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + dep_rpath="$dep_rpath $flag" + fi + elif test -n "$runpath_var"; then + case "$perm_rpath " in + *" $libdir "*) ;; + *) perm_rpath="$perm_rpath $libdir" ;; + esac + fi + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + if test -n "$hardcode_libdir_flag_spec_ld"; then + case $archive_cmds in + *\$LD*) eval dep_rpath=\"$hardcode_libdir_flag_spec_ld\" ;; + *) eval dep_rpath=\"$hardcode_libdir_flag_spec\" ;; + esac + else + eval dep_rpath=\"$hardcode_libdir_flag_spec\" + fi + fi + if test -n "$runpath_var" && test -n "$perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $perm_rpath; do + rpath="$rpath$dir:" + done + eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var" + fi + test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs" + fi + + shlibpath="$finalize_shlibpath" + test "$mode" != relink && shlibpath="$compile_shlibpath$shlibpath" + if test -n "$shlibpath"; then + eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var" + fi + + # Get the real and link names of the library. + eval shared_ext=\"$shrext_cmds\" + eval library_names=\"$library_names_spec\" + set dummy $library_names + realname="$2" + shift; shift + + if test -n "$soname_spec"; then + eval soname=\"$soname_spec\" + else + soname="$realname" + fi + if test -z "$dlname"; then + dlname=$soname + fi + + lib="$output_objdir/$realname" + linknames= + for link + do + linknames="$linknames $link" + done + + # Use standard objects if they are pic + test -z "$pic_flag" && libobjs=`$echo "X$libobjs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + + # Prepare the list of exported symbols + if test -z "$export_symbols"; then + if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then + $show "generating symbol list for \`$libname.la'" + export_symbols="$output_objdir/$libname.exp" + $run $rm $export_symbols + cmds=$export_symbols_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + if len=`expr "X$cmd" : ".*"` && + test "$len" -le "$max_cmd_len" || test "$max_cmd_len" -le -1; then + $show "$cmd" + $run eval "$cmd" || exit $? + skipped_export=false + else + # The command line is too long to execute in one step. + $show "using reloadable object file for export list..." + skipped_export=: + # Break out early, otherwise skipped_export may be + # set to false by a later but shorter cmd. + break + fi + done + IFS="$save_ifs" + if test -n "$export_symbols_regex"; then + $show "$EGREP -e \"$export_symbols_regex\" \"$export_symbols\" > \"${export_symbols}T\"" + $run eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' + $show "$mv \"${export_symbols}T\" \"$export_symbols\"" + $run eval '$mv "${export_symbols}T" "$export_symbols"' + fi + fi + fi + + if test -n "$export_symbols" && test -n "$include_expsyms"; then + $run eval '$echo "X$include_expsyms" | $SP2NL >> "$export_symbols"' + fi + + tmp_deplibs= + for test_deplib in $deplibs; do + case " $convenience " in + *" $test_deplib "*) ;; + *) + tmp_deplibs="$tmp_deplibs $test_deplib" + ;; + esac + done + deplibs="$tmp_deplibs" + + if test -n "$convenience"; then + if test -n "$whole_archive_flag_spec"; then + save_libobjs=$libobjs + eval libobjs=\"\$libobjs $whole_archive_flag_spec\" + else + gentop="$output_objdir/${outputname}x" + generated="$generated $gentop" + + func_extract_archives $gentop $convenience + libobjs="$libobjs $func_extract_archives_result" + fi + fi + + if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then + eval flag=\"$thread_safe_flag_spec\" + linker_flags="$linker_flags $flag" + fi + + # Make a backup of the uninstalled library when relinking + if test "$mode" = relink; then + $run eval '(cd $output_objdir && $rm ${realname}U && $mv $realname ${realname}U)' || exit $? + fi + + # Do each of the archive commands. + if test "$module" = yes && test -n "$module_cmds" ; then + if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then + eval test_cmds=\"$module_expsym_cmds\" + cmds=$module_expsym_cmds + else + eval test_cmds=\"$module_cmds\" + cmds=$module_cmds + fi + else + if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then + eval test_cmds=\"$archive_expsym_cmds\" + cmds=$archive_expsym_cmds + else + eval test_cmds=\"$archive_cmds\" + cmds=$archive_cmds + fi + fi + + if test "X$skipped_export" != "X:" && + len=`expr "X$test_cmds" : ".*" 2>/dev/null` && + test "$len" -le "$max_cmd_len" || test "$max_cmd_len" -le -1; then + : + else + # The command line is too long to link in one step, link piecewise. + $echo "creating reloadable object files..." + + # Save the value of $output and $libobjs because we want to + # use them later. If we have whole_archive_flag_spec, we + # want to use save_libobjs as it was before + # whole_archive_flag_spec was expanded, because we can't + # assume the linker understands whole_archive_flag_spec. + # This may have to be revisited, in case too many + # convenience libraries get linked in and end up exceeding + # the spec. + if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then + save_libobjs=$libobjs + fi + save_output=$output + output_la=`$echo "X$output" | $Xsed -e "$basename"` + + # Clear the reloadable object creation command queue and + # initialize k to one. + test_cmds= + concat_cmds= + objlist= + delfiles= + last_robj= + k=1 + output=$output_objdir/$output_la-${k}.$objext + # Loop over the list of objects to be linked. + for obj in $save_libobjs + do + eval test_cmds=\"$reload_cmds $objlist $last_robj\" + if test "X$objlist" = X || + { len=`expr "X$test_cmds" : ".*" 2>/dev/null` && + test "$len" -le "$max_cmd_len"; }; then + objlist="$objlist $obj" + else + # The command $test_cmds is almost too long, add a + # command to the queue. + if test "$k" -eq 1 ; then + # The first file doesn't have a previous command to add. + eval concat_cmds=\"$reload_cmds $objlist $last_robj\" + else + # All subsequent reloadable object files will link in + # the last one created. + eval concat_cmds=\"\$concat_cmds~$reload_cmds $objlist $last_robj\" + fi + last_robj=$output_objdir/$output_la-${k}.$objext + k=`expr $k + 1` + output=$output_objdir/$output_la-${k}.$objext + objlist=$obj + len=1 + fi + done + # Handle the remaining objects by creating one last + # reloadable object file. All subsequent reloadable object + # files will link in the last one created. + test -z "$concat_cmds" || concat_cmds=$concat_cmds~ + eval concat_cmds=\"\${concat_cmds}$reload_cmds $objlist $last_robj\" + + if ${skipped_export-false}; then + $show "generating symbol list for \`$libname.la'" + export_symbols="$output_objdir/$libname.exp" + $run $rm $export_symbols + libobjs=$output + # Append the command to create the export file. + eval concat_cmds=\"\$concat_cmds~$export_symbols_cmds\" + fi + + # Set up a command to remove the reloadable object files + # after they are used. + i=0 + while test "$i" -lt "$k" + do + i=`expr $i + 1` + delfiles="$delfiles $output_objdir/$output_la-${i}.$objext" + done + + $echo "creating a temporary reloadable object file: $output" + + # Loop through the commands generated above and execute them. + save_ifs="$IFS"; IFS='~' + for cmd in $concat_cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + + libobjs=$output + # Restore the value of output. + output=$save_output + + if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then + eval libobjs=\"\$libobjs $whole_archive_flag_spec\" + fi + # Expand the library linking commands again to reset the + # value of $libobjs for piecewise linking. + + # Do each of the archive commands. + if test "$module" = yes && test -n "$module_cmds" ; then + if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then + cmds=$module_expsym_cmds + else + cmds=$module_cmds + fi + else + if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then + cmds=$archive_expsym_cmds + else + cmds=$archive_cmds + fi + fi + + # Append the command to remove the reloadable object files + # to the just-reset $cmds. + eval cmds=\"\$cmds~\$rm $delfiles\" + fi + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" || { + lt_exit=$? + + # Restore the uninstalled library and exit + if test "$mode" = relink; then + $run eval '(cd $output_objdir && $rm ${realname}T && $mv ${realname}U $realname)' + fi + + exit $lt_exit + } + done + IFS="$save_ifs" + + # Restore the uninstalled library and exit + if test "$mode" = relink; then + $run eval '(cd $output_objdir && $rm ${realname}T && $mv $realname ${realname}T && $mv "$realname"U $realname)' || exit $? + + if test -n "$convenience"; then + if test -z "$whole_archive_flag_spec"; then + $show "${rm}r $gentop" + $run ${rm}r "$gentop" + fi + fi + + exit $EXIT_SUCCESS + fi + + # Create links to the real library. + for linkname in $linknames; do + if test "$realname" != "$linkname"; then + $show "(cd $output_objdir && $rm $linkname && $LN_S $realname $linkname)" + $run eval '(cd $output_objdir && $rm $linkname && $LN_S $realname $linkname)' || exit $? + fi + done + + # If -module or -export-dynamic was specified, set the dlname. + if test "$module" = yes || test "$export_dynamic" = yes; then + # On all known operating systems, these are identical. + dlname="$soname" + fi + fi + ;; + + obj) + case " $deplibs" in + *\ -l* | *\ -L*) + $echo "$modename: warning: \`-l' and \`-L' are ignored for objects" 1>&2 ;; + esac + + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + $echo "$modename: warning: \`-dlopen' is ignored for objects" 1>&2 + fi + + if test -n "$rpath"; then + $echo "$modename: warning: \`-rpath' is ignored for objects" 1>&2 + fi + + if test -n "$xrpath"; then + $echo "$modename: warning: \`-R' is ignored for objects" 1>&2 + fi + + if test -n "$vinfo"; then + $echo "$modename: warning: \`-version-info' is ignored for objects" 1>&2 + fi + + if test -n "$release"; then + $echo "$modename: warning: \`-release' is ignored for objects" 1>&2 + fi + + case $output in + *.lo) + if test -n "$objs$old_deplibs"; then + $echo "$modename: cannot build library object \`$output' from non-libtool objects" 1>&2 + exit $EXIT_FAILURE + fi + libobj="$output" + obj=`$echo "X$output" | $Xsed -e "$lo2o"` + ;; + *) + libobj= + obj="$output" + ;; + esac + + # Delete the old objects. + $run $rm $obj $libobj + + # Objects from convenience libraries. This assumes + # single-version convenience libraries. Whenever we create + # different ones for PIC/non-PIC, this we'll have to duplicate + # the extraction. + reload_conv_objs= + gentop= + # reload_cmds runs $LD directly, so let us get rid of + # -Wl from whole_archive_flag_spec and hope we can get by with + # turning comma into space.. + wl= + + if test -n "$convenience"; then + if test -n "$whole_archive_flag_spec"; then + eval tmp_whole_archive_flags=\"$whole_archive_flag_spec\" + reload_conv_objs=$reload_objs\ `$echo "X$tmp_whole_archive_flags" | $Xsed -e 's|,| |g'` + else + gentop="$output_objdir/${obj}x" + generated="$generated $gentop" + + func_extract_archives $gentop $convenience + reload_conv_objs="$reload_objs $func_extract_archives_result" + fi + fi + + # Create the old-style object. + reload_objs="$objs$old_deplibs "`$echo "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}$'/d' -e '/\.lib$/d' -e "$lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test + + output="$obj" + cmds=$reload_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + + # Exit if we aren't doing a library object file. + if test -z "$libobj"; then + if test -n "$gentop"; then + $show "${rm}r $gentop" + $run ${rm}r $gentop + fi + + exit $EXIT_SUCCESS + fi + + if test "$build_libtool_libs" != yes; then + if test -n "$gentop"; then + $show "${rm}r $gentop" + $run ${rm}r $gentop + fi + + # Create an invalid libtool object if no PIC, so that we don't + # accidentally link it into a program. + # $show "echo timestamp > $libobj" + # $run eval "echo timestamp > $libobj" || exit $? + exit $EXIT_SUCCESS + fi + + if test -n "$pic_flag" || test "$pic_mode" != default; then + # Only do commands if we really have different PIC objects. + reload_objs="$libobjs $reload_conv_objs" + output="$libobj" + cmds=$reload_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + fi + + if test -n "$gentop"; then + $show "${rm}r $gentop" + $run ${rm}r $gentop + fi + + exit $EXIT_SUCCESS + ;; + + prog) + case $host in + *cygwin*) output=`$echo $output | ${SED} -e 's,.exe$,,;s,$,.exe,'` ;; + esac + if test -n "$vinfo"; then + $echo "$modename: warning: \`-version-info' is ignored for programs" 1>&2 + fi + + if test -n "$release"; then + $echo "$modename: warning: \`-release' is ignored for programs" 1>&2 + fi + + if test "$preload" = yes; then + if test "$dlopen_support" = unknown && test "$dlopen_self" = unknown && + test "$dlopen_self_static" = unknown; then + $echo "$modename: warning: \`AC_LIBTOOL_DLOPEN' not used. Assuming no dlopen support." + fi + fi + + case $host in + *-*-rhapsody* | *-*-darwin1.[012]) + # On Rhapsody replace the C library is the System framework + compile_deplibs=`$echo "X $compile_deplibs" | $Xsed -e 's/ -lc / -framework System /'` + finalize_deplibs=`$echo "X $finalize_deplibs" | $Xsed -e 's/ -lc / -framework System /'` + ;; + esac + + case $host in + *darwin*) + # Don't allow lazy linking, it breaks C++ global constructors + if test "$tagname" = CXX ; then + compile_command="$compile_command ${wl}-bind_at_load" + finalize_command="$finalize_command ${wl}-bind_at_load" + fi + ;; + esac + + + # move library search paths that coincide with paths to not yet + # installed libraries to the beginning of the library search list + new_libs= + for path in $notinst_path; do + case " $new_libs " in + *" -L$path/$objdir "*) ;; + *) + case " $compile_deplibs " in + *" -L$path/$objdir "*) + new_libs="$new_libs -L$path/$objdir" ;; + esac + ;; + esac + done + for deplib in $compile_deplibs; do + case $deplib in + -L*) + case " $new_libs " in + *" $deplib "*) ;; + *) new_libs="$new_libs $deplib" ;; + esac + ;; + *) new_libs="$new_libs $deplib" ;; + esac + done + compile_deplibs="$new_libs" + + + compile_command="$compile_command $compile_deplibs" + finalize_command="$finalize_command $finalize_deplibs" + + if test -n "$rpath$xrpath"; then + # If the user specified any rpath flags, then add them. + for libdir in $rpath $xrpath; do + # This is the magic to use -rpath. + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" ;; + esac + done + fi + + # Now hardcode the library paths + rpath= + hardcode_libdirs= + for libdir in $compile_rpath $finalize_rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + rpath="$rpath $flag" + fi + elif test -n "$runpath_var"; then + case "$perm_rpath " in + *" $libdir "*) ;; + *) perm_rpath="$perm_rpath $libdir" ;; + esac + fi + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*) + testbindir=`$echo "X$libdir" | $Xsed -e 's*/lib$*/bin*'` + case :$dllsearchpath: in + *":$libdir:"*) ;; + *) dllsearchpath="$dllsearchpath:$libdir";; + esac + case :$dllsearchpath: in + *":$testbindir:"*) ;; + *) dllsearchpath="$dllsearchpath:$testbindir";; + esac + ;; + esac + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + eval rpath=\" $hardcode_libdir_flag_spec\" + fi + compile_rpath="$rpath" + + rpath= + hardcode_libdirs= + for libdir in $finalize_rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + rpath="$rpath $flag" + fi + elif test -n "$runpath_var"; then + case "$finalize_perm_rpath " in + *" $libdir "*) ;; + *) finalize_perm_rpath="$finalize_perm_rpath $libdir" ;; + esac + fi + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + eval rpath=\" $hardcode_libdir_flag_spec\" + fi + finalize_rpath="$rpath" + + if test -n "$libobjs" && test "$build_old_libs" = yes; then + # Transform all the library objects into standard objects. + compile_command=`$echo "X$compile_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + finalize_command=`$echo "X$finalize_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + fi + + dlsyms= + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + if test -n "$NM" && test -n "$global_symbol_pipe"; then + dlsyms="${outputname}S.c" + else + $echo "$modename: not configured to extract global symbols from dlpreopened files" 1>&2 + fi + fi + + if test -n "$dlsyms"; then + case $dlsyms in + "") ;; + *.c) + # Discover the nlist of each of the dlfiles. + nlist="$output_objdir/${outputname}.nm" + + $show "$rm $nlist ${nlist}S ${nlist}T" + $run $rm "$nlist" "${nlist}S" "${nlist}T" + + # Parse the name list into a source file. + $show "creating $output_objdir/$dlsyms" + + test -z "$run" && $echo > "$output_objdir/$dlsyms" "\ +/* $dlsyms - symbol resolution table for \`$outputname' dlsym emulation. */ +/* Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP */ + +#ifdef __cplusplus +extern \"C\" { +#endif + +/* Prevent the only kind of declaration conflicts we can make. */ +#define lt_preloaded_symbols some_other_symbol + +/* External symbol declarations for the compiler. */\ +" + + if test "$dlself" = yes; then + $show "generating symbol list for \`$output'" + + test -z "$run" && $echo ': @PROGRAM@ ' > "$nlist" + + # Add our own program objects to the symbol list. + progfiles=`$echo "X$objs$old_deplibs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + for arg in $progfiles; do + $show "extracting global C symbols from \`$arg'" + $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'" + done + + if test -n "$exclude_expsyms"; then + $run eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T' + $run eval '$mv "$nlist"T "$nlist"' + fi + + if test -n "$export_symbols_regex"; then + $run eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T' + $run eval '$mv "$nlist"T "$nlist"' + fi + + # Prepare the list of exported symbols + if test -z "$export_symbols"; then + export_symbols="$output_objdir/$outputname.exp" + $run $rm $export_symbols + $run eval "${SED} -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"' + case $host in + *cygwin* | *mingw* ) + $run eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' + $run eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"' + ;; + esac + else + $run eval "${SED} -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"' + $run eval 'grep -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T' + $run eval 'mv "$nlist"T "$nlist"' + case $host in + *cygwin* | *mingw* ) + $run eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' + $run eval 'cat "$nlist" >> "$output_objdir/$outputname.def"' + ;; + esac + fi + fi + + for arg in $dlprefiles; do + $show "extracting global C symbols from \`$arg'" + name=`$echo "$arg" | ${SED} -e 's%^.*/%%'` + $run eval '$echo ": $name " >> "$nlist"' + $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'" + done + + if test -z "$run"; then + # Make sure we have at least an empty file. + test -f "$nlist" || : > "$nlist" + + if test -n "$exclude_expsyms"; then + $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T + $mv "$nlist"T "$nlist" + fi + + # Try sorting and uniquifying the output. + if grep -v "^: " < "$nlist" | + if sort -k 3 /dev/null 2>&1; then + sort -k 3 + else + sort +2 + fi | + uniq > "$nlist"S; then + : + else + grep -v "^: " < "$nlist" > "$nlist"S + fi + + if test -f "$nlist"S; then + eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$dlsyms"' + else + $echo '/* NONE */' >> "$output_objdir/$dlsyms" + fi + + $echo >> "$output_objdir/$dlsyms" "\ + +#undef lt_preloaded_symbols + +#if defined (__STDC__) && __STDC__ +# define lt_ptr void * +#else +# define lt_ptr char * +# define const +#endif + +/* The mapping between symbol names and symbols. */ +" + + case $host in + *cygwin* | *mingw* ) + $echo >> "$output_objdir/$dlsyms" "\ +/* DATA imports from DLLs on WIN32 can't be const, because + runtime relocations are performed -- see ld's documentation + on pseudo-relocs */ +struct { +" + ;; + * ) + $echo >> "$output_objdir/$dlsyms" "\ +const struct { +" + ;; + esac + + + $echo >> "$output_objdir/$dlsyms" "\ + const char *name; + lt_ptr address; +} +lt_preloaded_symbols[] = +{\ +" + + eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$dlsyms" + + $echo >> "$output_objdir/$dlsyms" "\ + {0, (lt_ptr) 0} +}; + +/* This works around a problem in FreeBSD linker */ +#ifdef FREEBSD_WORKAROUND +static const void *lt_preloaded_setup() { + return lt_preloaded_symbols; +} +#endif + +#ifdef __cplusplus +} +#endif\ +" + fi + + pic_flag_for_symtable= + case $host in + # compiling the symbol table file with pic_flag works around + # a FreeBSD bug that causes programs to crash when -lm is + # linked before any other PIC object. But we must not use + # pic_flag when linking with -static. The problem exists in + # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1. + *-*-freebsd2*|*-*-freebsd3.0*|*-*-freebsdelf3.0*) + case "$compile_command " in + *" -static "*) ;; + *) pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND";; + esac;; + *-*-hpux*) + case "$compile_command " in + *" -static "*) ;; + *) pic_flag_for_symtable=" $pic_flag";; + esac + esac + + # Now compile the dynamic symbol file. + $show "(cd $output_objdir && $LTCC $LTCFLAGS -c$no_builtin_flag$pic_flag_for_symtable \"$dlsyms\")" + $run eval '(cd $output_objdir && $LTCC $LTCFLAGS -c$no_builtin_flag$pic_flag_for_symtable "$dlsyms")' || exit $? + + # Clean up the generated files. + $show "$rm $output_objdir/$dlsyms $nlist ${nlist}S ${nlist}T" + $run $rm "$output_objdir/$dlsyms" "$nlist" "${nlist}S" "${nlist}T" + + # Transform the symbol file into the correct name. + case $host in + *cygwin* | *mingw* ) + if test -f "$output_objdir/${outputname}.def" ; then + compile_command=`$echo "X$compile_command" | $SP2NL | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}.def $output_objdir/${outputname}S.${objext}%" | $NL2SP` + finalize_command=`$echo "X$finalize_command" | $SP2NL | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}.def $output_objdir/${outputname}S.${objext}%" | $NL2SP` + else + compile_command=`$echo "X$compile_command" | $SP2NL | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%" | $NL2SP` + finalize_command=`$echo "X$finalize_command" | $SP2NL | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%" | $NL2SP` + fi + ;; + * ) + compile_command=`$echo "X$compile_command" | $SP2NL | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%" | $NL2SP` + finalize_command=`$echo "X$finalize_command" | $SP2NL | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%" | $NL2SP` + ;; + esac + ;; + *) + $echo "$modename: unknown suffix for \`$dlsyms'" 1>&2 + exit $EXIT_FAILURE + ;; + esac + else + # We keep going just in case the user didn't refer to + # lt_preloaded_symbols. The linker will fail if global_symbol_pipe + # really was required. + + # Nullify the symbol file. + compile_command=`$echo "X$compile_command" | $SP2NL | $Xsed -e "s% @SYMFILE@%%" | $NL2SP` + finalize_command=`$echo "X$finalize_command" | $SP2NL | $Xsed -e "s% @SYMFILE@%%" | $NL2SP` + fi + + if test "$need_relink" = no || test "$build_libtool_libs" != yes; then + # Replace the output file specification. + compile_command=`$echo "X$compile_command" | $SP2NL | $Xsed -e 's%@OUTPUT@%'"$output"'%g' | $NL2SP` + link_command="$compile_command$compile_rpath" + + # We have no uninstalled library dependencies, so finalize right now. + $show "$link_command" + $run eval "$link_command" + exit_status=$? + + # Delete the generated files. + if test -n "$dlsyms"; then + $show "$rm $output_objdir/${outputname}S.${objext}" + $run $rm "$output_objdir/${outputname}S.${objext}" + fi + + exit $exit_status + fi + + if test -n "$shlibpath_var"; then + # We should set the shlibpath_var + rpath= + for dir in $temp_rpath; do + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) + # Absolute path. + rpath="$rpath$dir:" + ;; + *) + # Relative path: add a thisdir entry. + rpath="$rpath\$thisdir/$dir:" + ;; + esac + done + temp_rpath="$rpath" + fi + + if test -n "$compile_shlibpath$finalize_shlibpath"; then + compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command" + fi + if test -n "$finalize_shlibpath"; then + finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command" + fi + + compile_var= + finalize_var= + if test -n "$runpath_var"; then + if test -n "$perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $perm_rpath; do + rpath="$rpath$dir:" + done + compile_var="$runpath_var=\"$rpath\$$runpath_var\" " + fi + if test -n "$finalize_perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $finalize_perm_rpath; do + rpath="$rpath$dir:" + done + finalize_var="$runpath_var=\"$rpath\$$runpath_var\" " + fi + fi + + if test "$no_install" = yes; then + # We don't need to create a wrapper script. + link_command="$compile_var$compile_command$compile_rpath" + # Replace the output file specification. + link_command=`$echo "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'` + # Delete the old output file. + $run $rm $output + # Link the executable and exit + $show "$link_command" + $run eval "$link_command" || exit $? + exit $EXIT_SUCCESS + fi + + if test "$hardcode_action" = relink; then + # Fast installation is not supported + link_command="$compile_var$compile_command$compile_rpath" + relink_command="$finalize_var$finalize_command$finalize_rpath" + + $echo "$modename: warning: this platform does not like uninstalled shared libraries" 1>&2 + $echo "$modename: \`$output' will be relinked during installation" 1>&2 + else + if test "$fast_install" != no; then + link_command="$finalize_var$compile_command$finalize_rpath" + if test "$fast_install" = yes; then + relink_command=`$echo "X$compile_var$compile_command$compile_rpath" | $SP2NL | $Xsed -e 's%@OUTPUT@%\$progdir/\$file%g' | $NL2SP` + else + # fast_install is set to needless + relink_command= + fi + else + link_command="$compile_var$compile_command$compile_rpath" + relink_command="$finalize_var$finalize_command$finalize_rpath" + fi + fi + + # Replace the output file specification. + link_command=`$echo "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'` + + # Delete the old output files. + $run $rm $output $output_objdir/$outputname $output_objdir/lt-$outputname + + $show "$link_command" + $run eval "$link_command" || exit $? + + # Now create the wrapper script. + $show "creating $output" + + # Quote the relink command for shipping. + if test -n "$relink_command"; then + # Preserve any variables that may affect compiler behavior + for var in $variables_saved_for_relink; do + if eval test -z \"\${$var+set}\"; then + relink_command="{ test -z \"\${$var+set}\" || unset $var || { $var=; export $var; }; }; $relink_command" + elif eval var_value=\$$var; test -z "$var_value"; then + relink_command="$var=; export $var; $relink_command" + else + var_value=`$echo "X$var_value" | $Xsed -e "$sed_quote_subst"` + relink_command="$var=\"$var_value\"; export $var; $relink_command" + fi + done + relink_command="(cd `pwd`; $relink_command)" + relink_command=`$echo "X$relink_command" | $SP2NL | $Xsed -e "$sed_quote_subst" | $NL2SP` + fi + + # Quote $echo for shipping. + if test "X$echo" = "X$SHELL $progpath --fallback-echo"; then + case $progpath in + [\\/]* | [A-Za-z]:[\\/]*) qecho="$SHELL $progpath --fallback-echo";; + *) qecho="$SHELL `pwd`/$progpath --fallback-echo";; + esac + qecho=`$echo "X$qecho" | $Xsed -e "$sed_quote_subst"` + else + qecho=`$echo "X$echo" | $Xsed -e "$sed_quote_subst"` + fi + + # Only actually do things if our run command is non-null. + if test -z "$run"; then + # win32 will think the script is a binary if it has + # a .exe suffix, so we strip it off here. + case $output in + *.exe) output=`$echo $output|${SED} 's,.exe$,,'` ;; + esac + # test for cygwin because mv fails w/o .exe extensions + case $host in + *cygwin*) + exeext=.exe + outputname=`$echo $outputname|${SED} 's,.exe$,,'` ;; + *) exeext= ;; + esac + case $host in + *cygwin* | *mingw* ) + output_name=`basename $output` + output_path=`dirname $output` + cwrappersource="$output_path/$objdir/lt-$output_name.c" + cwrapper="$output_path/$output_name.exe" + $rm $cwrappersource $cwrapper + trap "$rm $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15 + + cat > $cwrappersource <> $cwrappersource<<"EOF" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(PATH_MAX) +# define LT_PATHMAX PATH_MAX +#elif defined(MAXPATHLEN) +# define LT_PATHMAX MAXPATHLEN +#else +# define LT_PATHMAX 1024 +#endif + +#ifndef DIR_SEPARATOR +# define DIR_SEPARATOR '/' +# define PATH_SEPARATOR ':' +#endif + +#if defined (_WIN32) || defined (__MSDOS__) || defined (__DJGPP__) || \ + defined (__OS2__) +# define HAVE_DOS_BASED_FILE_SYSTEM +# ifndef DIR_SEPARATOR_2 +# define DIR_SEPARATOR_2 '\\' +# endif +# ifndef PATH_SEPARATOR_2 +# define PATH_SEPARATOR_2 ';' +# endif +#endif + +#ifndef DIR_SEPARATOR_2 +# define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR) +#else /* DIR_SEPARATOR_2 */ +# define IS_DIR_SEPARATOR(ch) \ + (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2)) +#endif /* DIR_SEPARATOR_2 */ + +#ifndef PATH_SEPARATOR_2 +# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR) +#else /* PATH_SEPARATOR_2 */ +# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2) +#endif /* PATH_SEPARATOR_2 */ + +#define XMALLOC(type, num) ((type *) xmalloc ((num) * sizeof(type))) +#define XFREE(stale) do { \ + if (stale) { free ((void *) stale); stale = 0; } \ +} while (0) + +/* -DDEBUG is fairly common in CFLAGS. */ +#undef DEBUG +#if defined DEBUGWRAPPER +# define DEBUG(format, ...) fprintf(stderr, format, __VA_ARGS__) +#else +# define DEBUG(format, ...) +#endif + +const char *program_name = NULL; + +void * xmalloc (size_t num); +char * xstrdup (const char *string); +const char * base_name (const char *name); +char * find_executable(const char *wrapper); +int check_executable(const char *path); +char * strendzap(char *str, const char *pat); +void lt_fatal (const char *message, ...); + +int +main (int argc, char *argv[]) +{ + char **newargz; + int i; + + program_name = (char *) xstrdup (base_name (argv[0])); + DEBUG("(main) argv[0] : %s\n",argv[0]); + DEBUG("(main) program_name : %s\n",program_name); + newargz = XMALLOC(char *, argc+2); +EOF + + cat >> $cwrappersource <> $cwrappersource <<"EOF" + newargz[1] = find_executable(argv[0]); + if (newargz[1] == NULL) + lt_fatal("Couldn't find %s", argv[0]); + DEBUG("(main) found exe at : %s\n",newargz[1]); + /* we know the script has the same name, without the .exe */ + /* so make sure newargz[1] doesn't end in .exe */ + strendzap(newargz[1],".exe"); + for (i = 1; i < argc; i++) + newargz[i+1] = xstrdup(argv[i]); + newargz[argc+1] = NULL; + + for (i=0; i> $cwrappersource <> $cwrappersource <> $cwrappersource <<"EOF" + return 127; +} + +void * +xmalloc (size_t num) +{ + void * p = (void *) malloc (num); + if (!p) + lt_fatal ("Memory exhausted"); + + return p; +} + +char * +xstrdup (const char *string) +{ + return string ? strcpy ((char *) xmalloc (strlen (string) + 1), string) : NULL +; +} + +const char * +base_name (const char *name) +{ + const char *base; + +#if defined (HAVE_DOS_BASED_FILE_SYSTEM) + /* Skip over the disk name in MSDOS pathnames. */ + if (isalpha ((unsigned char)name[0]) && name[1] == ':') + name += 2; +#endif + + for (base = name; *name; name++) + if (IS_DIR_SEPARATOR (*name)) + base = name + 1; + return base; +} + +int +check_executable(const char * path) +{ + struct stat st; + + DEBUG("(check_executable) : %s\n", path ? (*path ? path : "EMPTY!") : "NULL!"); + if ((!path) || (!*path)) + return 0; + + if ((stat (path, &st) >= 0) && + ( + /* MinGW & native WIN32 do not support S_IXOTH or S_IXGRP */ +#if defined (S_IXOTH) + ((st.st_mode & S_IXOTH) == S_IXOTH) || +#endif +#if defined (S_IXGRP) + ((st.st_mode & S_IXGRP) == S_IXGRP) || +#endif + ((st.st_mode & S_IXUSR) == S_IXUSR)) + ) + return 1; + else + return 0; +} + +/* Searches for the full path of the wrapper. Returns + newly allocated full path name if found, NULL otherwise */ +char * +find_executable (const char* wrapper) +{ + int has_slash = 0; + const char* p; + const char* p_next; + /* static buffer for getcwd */ + char tmp[LT_PATHMAX + 1]; + int tmp_len; + char* concat_name; + + DEBUG("(find_executable) : %s\n", wrapper ? (*wrapper ? wrapper : "EMPTY!") : "NULL!"); + + if ((wrapper == NULL) || (*wrapper == '\0')) + return NULL; + + /* Absolute path? */ +#if defined (HAVE_DOS_BASED_FILE_SYSTEM) + if (isalpha ((unsigned char)wrapper[0]) && wrapper[1] == ':') + { + concat_name = xstrdup (wrapper); + if (check_executable(concat_name)) + return concat_name; + XFREE(concat_name); + } + else + { +#endif + if (IS_DIR_SEPARATOR (wrapper[0])) + { + concat_name = xstrdup (wrapper); + if (check_executable(concat_name)) + return concat_name; + XFREE(concat_name); + } +#if defined (HAVE_DOS_BASED_FILE_SYSTEM) + } +#endif + + for (p = wrapper; *p; p++) + if (*p == '/') + { + has_slash = 1; + break; + } + if (!has_slash) + { + /* no slashes; search PATH */ + const char* path = getenv ("PATH"); + if (path != NULL) + { + for (p = path; *p; p = p_next) + { + const char* q; + size_t p_len; + for (q = p; *q; q++) + if (IS_PATH_SEPARATOR(*q)) + break; + p_len = q - p; + p_next = (*q == '\0' ? q : q + 1); + if (p_len == 0) + { + /* empty path: current directory */ + if (getcwd (tmp, LT_PATHMAX) == NULL) + lt_fatal ("getcwd failed"); + tmp_len = strlen(tmp); + concat_name = XMALLOC(char, tmp_len + 1 + strlen(wrapper) + 1); + memcpy (concat_name, tmp, tmp_len); + concat_name[tmp_len] = '/'; + strcpy (concat_name + tmp_len + 1, wrapper); + } + else + { + concat_name = XMALLOC(char, p_len + 1 + strlen(wrapper) + 1); + memcpy (concat_name, p, p_len); + concat_name[p_len] = '/'; + strcpy (concat_name + p_len + 1, wrapper); + } + if (check_executable(concat_name)) + return concat_name; + XFREE(concat_name); + } + } + /* not found in PATH; assume curdir */ + } + /* Relative path | not found in path: prepend cwd */ + if (getcwd (tmp, LT_PATHMAX) == NULL) + lt_fatal ("getcwd failed"); + tmp_len = strlen(tmp); + concat_name = XMALLOC(char, tmp_len + 1 + strlen(wrapper) + 1); + memcpy (concat_name, tmp, tmp_len); + concat_name[tmp_len] = '/'; + strcpy (concat_name + tmp_len + 1, wrapper); + + if (check_executable(concat_name)) + return concat_name; + XFREE(concat_name); + return NULL; +} + +char * +strendzap(char *str, const char *pat) +{ + size_t len, patlen; + + assert(str != NULL); + assert(pat != NULL); + + len = strlen(str); + patlen = strlen(pat); + + if (patlen <= len) + { + str += len - patlen; + if (strcmp(str, pat) == 0) + *str = '\0'; + } + return str; +} + +static void +lt_error_core (int exit_status, const char * mode, + const char * message, va_list ap) +{ + fprintf (stderr, "%s: %s: ", program_name, mode); + vfprintf (stderr, message, ap); + fprintf (stderr, ".\n"); + + if (exit_status >= 0) + exit (exit_status); +} + +void +lt_fatal (const char *message, ...) +{ + va_list ap; + va_start (ap, message); + lt_error_core (EXIT_FAILURE, "FATAL", message, ap); + va_end (ap); +} +EOF + # we should really use a build-platform specific compiler + # here, but OTOH, the wrappers (shell script and this C one) + # are only useful if you want to execute the "real" binary. + # Since the "real" binary is built for $host, then this + # wrapper might as well be built for $host, too. + $run $LTCC $LTCFLAGS -s -o $cwrapper $cwrappersource + ;; + esac + $rm $output + trap "$rm $output; exit $EXIT_FAILURE" 1 2 15 + + $echo > $output "\ +#! $SHELL + +# $output - temporary wrapper script for $objdir/$outputname +# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP +# +# The $output program cannot be directly executed until all the libtool +# libraries that it depends on are installed. +# +# This wrapper script should never be moved out of the build directory. +# If it is, it will not operate correctly. + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +Xsed='${SED} -e 1s/^X//' +sed_quote_subst='$sed_quote_subst' + +# Be Bourne compatible (taken from Autoconf:_AS_BOURNE_COMPATIBLE). +if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs 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 +BIN_SH=xpg4; export BIN_SH # for Tru64 +DUALCASE=1; export DUALCASE # for MKS sh + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +relink_command=\"$relink_command\" + +# This environment variable determines our operation mode. +if test \"\$libtool_install_magic\" = \"$magic\"; then + # install mode needs the following variable: + notinst_deplibs='$notinst_deplibs' +else + # When we are sourced in execute mode, \$file and \$echo are already set. + if test \"\$libtool_execute_magic\" != \"$magic\"; then + echo=\"$qecho\" + file=\"\$0\" + # Make sure echo works. + if test \"X\$1\" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift + elif test \"X\`(\$echo '\t') 2>/dev/null\`\" = 'X\t'; then + # Yippee, \$echo works! + : + else + # Restart under the correct shell, and then maybe \$echo will work. + exec $SHELL \"\$0\" --no-reexec \${1+\"\$@\"} + fi + fi\ +" + $echo >> $output "\ + + # Find the directory that this script lives in. + thisdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*$%%'\` + test \"x\$thisdir\" = \"x\$file\" && thisdir=. + + # Follow symbolic links until we get to the real thisdir. + file=\`ls -ld \"\$file\" | ${SED} -n 's/.*-> //p'\` + while test -n \"\$file\"; do + destdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*\$%%'\` + + # If there was a directory component, then change thisdir. + if test \"x\$destdir\" != \"x\$file\"; then + case \"\$destdir\" in + [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;; + *) thisdir=\"\$thisdir/\$destdir\" ;; + esac + fi + + file=\`\$echo \"X\$file\" | \$Xsed -e 's%^.*/%%'\` + file=\`ls -ld \"\$thisdir/\$file\" | ${SED} -n 's/.*-> //p'\` + done + + # Try to get the absolute directory name. + absdir=\`cd \"\$thisdir\" && pwd\` + test -n \"\$absdir\" && thisdir=\"\$absdir\" +" + + if test "$fast_install" = yes; then + $echo >> $output "\ + program=lt-'$outputname'$exeext + progdir=\"\$thisdir/$objdir\" + + if test ! -f \"\$progdir/\$program\" || \\ + { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | ${SED} 1q\`; \\ + test \"X\$file\" != \"X\$progdir/\$program\"; }; then + + file=\"\$\$-\$program\" + + if test ! -d \"\$progdir\"; then + $mkdir \"\$progdir\" + else + $rm \"\$progdir/\$file\" + fi" + + $echo >> $output "\ + + # relink executable if necessary + if test -n \"\$relink_command\"; then + if relink_command_output=\`eval \$relink_command 2>&1\`; then : + else + $echo \"\$relink_command_output\" >&2 + $rm \"\$progdir/\$file\" + exit $EXIT_FAILURE + fi + fi + + $mv \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null || + { $rm \"\$progdir/\$program\"; + $mv \"\$progdir/\$file\" \"\$progdir/\$program\"; } + $rm \"\$progdir/\$file\" + fi" + else + $echo >> $output "\ + program='$outputname' + progdir=\"\$thisdir/$objdir\" +" + fi + + $echo >> $output "\ + + if test -f \"\$progdir/\$program\"; then" + + # Export our shlibpath_var if we have one. + if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then + $echo >> $output "\ + # Add our own library path to $shlibpath_var + $shlibpath_var=\"$temp_rpath\$$shlibpath_var\" + + # Some systems cannot cope with colon-terminated $shlibpath_var + # The second colon is a workaround for a bug in BeOS R4 sed + $shlibpath_var=\`\$echo \"X\$$shlibpath_var\" | \$Xsed -e 's/::*\$//'\` + + export $shlibpath_var +" + fi + + # fixup the dll searchpath if we need to. + if test -n "$dllsearchpath"; then + $echo >> $output "\ + # Add the dll search path components to the executable PATH + PATH=$dllsearchpath:\$PATH +" + fi + + $echo >> $output "\ + if test \"\$libtool_execute_magic\" != \"$magic\"; then + # Run the actual program with our arguments. +" + case $host in + # Backslashes separate directories on plain windows + *-*-mingw | *-*-os2*) + $echo >> $output "\ + exec \"\$progdir\\\\\$program\" \${1+\"\$@\"} +" + ;; + + *) + $echo >> $output "\ + exec \"\$progdir/\$program\" \${1+\"\$@\"} +" + ;; + esac + $echo >> $output "\ + \$echo \"\$0: cannot exec \$program \$*\" + exit $EXIT_FAILURE + fi + else + # The program doesn't exist. + \$echo \"\$0: error: \\\`\$progdir/\$program' does not exist\" 1>&2 + \$echo \"This script is just a wrapper for \$program.\" 1>&2 + $echo \"See the $PACKAGE documentation for more information.\" 1>&2 + exit $EXIT_FAILURE + fi +fi\ +" + chmod +x $output + fi + exit $EXIT_SUCCESS + ;; + esac + + # See if we need to build an old-fashioned archive. + for oldlib in $oldlibs; do + + if test "$build_libtool_libs" = convenience; then + oldobjs="$libobjs_save" + addlibs="$convenience" + build_libtool_libs=no + else + if test "$build_libtool_libs" = module; then + oldobjs="$libobjs_save" + build_libtool_libs=no + else + oldobjs="$old_deplibs $non_pic_objects" + fi + addlibs="$old_convenience" + fi + + if test -n "$addlibs"; then + gentop="$output_objdir/${outputname}x" + generated="$generated $gentop" + + func_extract_archives $gentop $addlibs + oldobjs="$oldobjs $func_extract_archives_result" + fi + + # Do each command in the archive commands. + if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then + cmds=$old_archive_from_new_cmds + else + # POSIX demands no paths to be encoded in archives. We have + # to avoid creating archives with duplicate basenames if we + # might have to extract them afterwards, e.g., when creating a + # static archive out of a convenience library, or when linking + # the entirety of a libtool archive into another (currently + # not supported by libtool). + if (for obj in $oldobjs + do + $echo "X$obj" | $Xsed -e 's%^.*/%%' + done | sort | sort -uc >/dev/null 2>&1); then + : + else + $echo "copying selected object files to avoid basename conflicts..." + + if test -z "$gentop"; then + gentop="$output_objdir/${outputname}x" + generated="$generated $gentop" + + $show "${rm}r $gentop" + $run ${rm}r "$gentop" + $show "$mkdir $gentop" + $run $mkdir "$gentop" + exit_status=$? + if test "$exit_status" -ne 0 && test ! -d "$gentop"; then + exit $exit_status + fi + fi + + save_oldobjs=$oldobjs + oldobjs= + counter=1 + for obj in $save_oldobjs + do + objbase=`$echo "X$obj" | $Xsed -e 's%^.*/%%'` + case " $oldobjs " in + " ") oldobjs=$obj ;; + *[\ /]"$objbase "*) + while :; do + # Make sure we don't pick an alternate name that also + # overlaps. + newobj=lt$counter-$objbase + counter=`expr $counter + 1` + case " $oldobjs " in + *[\ /]"$newobj "*) ;; + *) if test ! -f "$gentop/$newobj"; then break; fi ;; + esac + done + $show "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj" + $run ln "$obj" "$gentop/$newobj" || + $run cp "$obj" "$gentop/$newobj" + oldobjs="$oldobjs $gentop/$newobj" + ;; + *) oldobjs="$oldobjs $obj" ;; + esac + done + fi + + eval cmds=\"$old_archive_cmds\" + + if len=`expr "X$cmds" : ".*"` && + test "$len" -le "$max_cmd_len" || test "$max_cmd_len" -le -1; then + cmds=$old_archive_cmds + else + # the command line is too long to link in one step, link in parts + $echo "using piecewise archive linking..." + save_RANLIB=$RANLIB + RANLIB=: + objlist= + concat_cmds= + save_oldobjs=$oldobjs + + # Is there a better way of finding the last object in the list? + for obj in $save_oldobjs + do + last_oldobj=$obj + done + for obj in $save_oldobjs + do + oldobjs="$objlist $obj" + objlist="$objlist $obj" + eval test_cmds=\"$old_archive_cmds\" + if len=`expr "X$test_cmds" : ".*" 2>/dev/null` && + test "$len" -le "$max_cmd_len"; then + : + else + # the above command should be used before it gets too long + oldobjs=$objlist + if test "$obj" = "$last_oldobj" ; then + RANLIB=$save_RANLIB + fi + test -z "$concat_cmds" || concat_cmds=$concat_cmds~ + eval concat_cmds=\"\${concat_cmds}$old_archive_cmds\" + objlist= + fi + done + RANLIB=$save_RANLIB + oldobjs=$objlist + if test "X$oldobjs" = "X" ; then + eval cmds=\"\$concat_cmds\" + else + eval cmds=\"\$concat_cmds~\$old_archive_cmds\" + fi + fi + fi + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + eval cmd=\"$cmd\" + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + done + + if test -n "$generated"; then + $show "${rm}r$generated" + $run ${rm}r$generated + fi + + # Now create the libtool archive. + case $output in + *.la) + old_library= + test "$build_old_libs" = yes && old_library="$libname.$libext" + $show "creating $output" + + # Preserve any variables that may affect compiler behavior + for var in $variables_saved_for_relink; do + if eval test -z \"\${$var+set}\"; then + relink_command="{ test -z \"\${$var+set}\" || unset $var || { $var=; export $var; }; }; $relink_command" + elif eval var_value=\$$var; test -z "$var_value"; then + relink_command="$var=; export $var; $relink_command" + else + var_value=`$echo "X$var_value" | $Xsed -e "$sed_quote_subst"` + relink_command="$var=\"$var_value\"; export $var; $relink_command" + fi + done + # Quote the link command for shipping. + relink_command="(cd `pwd`; $SHELL $progpath $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)" + relink_command=`$echo "X$relink_command" | $SP2NL | $Xsed -e "$sed_quote_subst" | $NL2SP` + if test "$hardcode_automatic" = yes ; then + relink_command= + fi + + + # Only create the output if not a dry run. + if test -z "$run"; then + for installed in no yes; do + if test "$installed" = yes; then + if test -z "$install_libdir"; then + break + fi + output="$output_objdir/$outputname"i + # Replace all uninstalled libtool libraries with the installed ones + newdependency_libs= + for deplib in $dependency_libs; do + case $deplib in + *.la) + name=`$echo "X$deplib" | $Xsed -e 's%^.*/%%'` + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` + if test -z "$libdir"; then + $echo "$modename: \`$deplib' is not a valid libtool archive" 1>&2 + exit $EXIT_FAILURE + fi + newdependency_libs="$newdependency_libs $libdir/$name" + ;; + *) newdependency_libs="$newdependency_libs $deplib" ;; + esac + done + dependency_libs="$newdependency_libs" + newdlfiles= + for lib in $dlfiles; do + name=`$echo "X$lib" | $Xsed -e 's%^.*/%%'` + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` + if test -z "$libdir"; then + $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 + exit $EXIT_FAILURE + fi + newdlfiles="$newdlfiles $libdir/$name" + done + dlfiles="$newdlfiles" + newdlprefiles= + for lib in $dlprefiles; do + name=`$echo "X$lib" | $Xsed -e 's%^.*/%%'` + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` + if test -z "$libdir"; then + $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 + exit $EXIT_FAILURE + fi + newdlprefiles="$newdlprefiles $libdir/$name" + done + dlprefiles="$newdlprefiles" + else + newdlfiles= + for lib in $dlfiles; do + case $lib in + [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; + *) abs=`pwd`"/$lib" ;; + esac + newdlfiles="$newdlfiles $abs" + done + dlfiles="$newdlfiles" + newdlprefiles= + for lib in $dlprefiles; do + case $lib in + [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; + *) abs=`pwd`"/$lib" ;; + esac + newdlprefiles="$newdlprefiles $abs" + done + dlprefiles="$newdlprefiles" + fi + $rm $output + # place dlname in correct position for cygwin + tdlname=$dlname + case $host,$output,$installed,$module,$dlname in + *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll) tdlname=../bin/$dlname ;; + esac + $echo > $output "\ +# $outputname - a libtool library file +# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# The name that we can dlopen(3). +dlname='$tdlname' + +# Names of this library. +library_names='$library_names' + +# The name of the static archive. +old_library='$old_library' + +# Libraries that this one depends upon. +dependency_libs='$dependency_libs' + +# Version information for $libname. +current=$current +age=$age +revision=$revision + +# Is this an already installed library? +installed=$installed + +# Should we warn about portability when linking against -modules? +shouldnotlink=$module + +# Files to dlopen/dlpreopen +dlopen='$dlfiles' +dlpreopen='$dlprefiles' + +# Directory that this library needs to be installed in: +libdir='$install_libdir'" + if test "$installed" = no && test "$need_relink" = yes; then + $echo >> $output "\ +relink_command=\"$relink_command\"" + fi + done + fi + + # Do a symbolic link so that the libtool archive can be found in + # LD_LIBRARY_PATH before the program is installed. + $show "(cd $output_objdir && $rm $outputname && $LN_S ../$outputname $outputname)" + $run eval '(cd $output_objdir && $rm $outputname && $LN_S ../$outputname $outputname)' || exit $? + ;; + esac + exit $EXIT_SUCCESS + ;; + + # libtool install mode + install) + modename="$modename: install" + + # There may be an optional sh(1) argument at the beginning of + # install_prog (especially on Windows NT). + if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh || + # Allow the use of GNU shtool's install command. + $echo "X$nonopt" | grep shtool > /dev/null; then + # Aesthetically quote it. + arg=`$echo "X$nonopt" | $Xsed -e "$sed_quote_subst"` + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + install_prog="$arg " + arg="$1" + shift + else + install_prog= + arg=$nonopt + fi + + # The real first argument should be the name of the installation program. + # Aesthetically quote it. + arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + install_prog="$install_prog$arg" + + # We need to accept at least all the BSD install flags. + dest= + files= + opts= + prev= + install_type= + isdir=no + stripme= + for arg + do + if test -n "$dest"; then + files="$files $dest" + dest=$arg + continue + fi + + case $arg in + -d) isdir=yes ;; + -f) + case " $install_prog " in + *[\\\ /]cp\ *) ;; + *) prev=$arg ;; + esac + ;; + -g | -m | -o) prev=$arg ;; + -s) + stripme=" -s" + continue + ;; + -*) + ;; + *) + # If the previous option needed an argument, then skip it. + if test -n "$prev"; then + prev= + else + dest=$arg + continue + fi + ;; + esac + + # Aesthetically quote the argument. + arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + install_prog="$install_prog $arg" + done + + if test -z "$install_prog"; then + $echo "$modename: you must specify an install program" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + if test -n "$prev"; then + $echo "$modename: the \`$prev' option requires an argument" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + if test -z "$files"; then + if test -z "$dest"; then + $echo "$modename: no file or destination specified" 1>&2 + else + $echo "$modename: you must specify a destination" 1>&2 + fi + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + # Strip any trailing slash from the destination. + dest=`$echo "X$dest" | $Xsed -e 's%/$%%'` + + # Check to see that the destination is a directory. + test -d "$dest" && isdir=yes + if test "$isdir" = yes; then + destdir="$dest" + destname= + else + destdir=`$echo "X$dest" | $Xsed -e 's%/[^/]*$%%'` + test "X$destdir" = "X$dest" && destdir=. + destname=`$echo "X$dest" | $Xsed -e 's%^.*/%%'` + + # Not a directory, so check to see that there is only one file specified. + set dummy $files + if test "$#" -gt 2; then + $echo "$modename: \`$dest' is not a directory" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + fi + case $destdir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + for file in $files; do + case $file in + *.lo) ;; + *) + $echo "$modename: \`$destdir' must be an absolute directory name" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + ;; + esac + done + ;; + esac + + # This variable tells wrapper scripts just to set variables rather + # than running their programs. + libtool_install_magic="$magic" + + staticlibs= + future_libdirs= + current_libdirs= + for file in $files; do + + # Do each installation. + case $file in + *.$libext) + # Do the static libraries later. + staticlibs="$staticlibs $file" + ;; + + *.la) + # Check to see that this really is a libtool archive. + if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then : + else + $echo "$modename: \`$file' is not a valid libtool archive" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + library_names= + old_library= + relink_command= + # If there is no directory component, then add one. + case $file in + */* | *\\*) . $file ;; + *) . ./$file ;; + esac + + # Add the libdir to current_libdirs if it is the destination. + if test "X$destdir" = "X$libdir"; then + case "$current_libdirs " in + *" $libdir "*) ;; + *) current_libdirs="$current_libdirs $libdir" ;; + esac + else + # Note the libdir as a future libdir. + case "$future_libdirs " in + *" $libdir "*) ;; + *) future_libdirs="$future_libdirs $libdir" ;; + esac + fi + + dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`/ + test "X$dir" = "X$file/" && dir= + dir="$dir$objdir" + + if test -n "$relink_command"; then + # Determine the prefix the user has applied to our future dir. + inst_prefix_dir=`$echo "$destdir" | $SED "s%$libdir\$%%"` + + # Don't allow the user to place us outside of our expected + # location b/c this prevents finding dependent libraries that + # are installed to the same prefix. + # At present, this check doesn't affect windows .dll's that + # are installed into $libdir/../bin (currently, that works fine) + # but it's something to keep an eye on. + if test "$inst_prefix_dir" = "$destdir"; then + $echo "$modename: error: cannot install \`$file' to a directory not ending in $libdir" 1>&2 + exit $EXIT_FAILURE + fi + + if test -n "$inst_prefix_dir"; then + # Stick the inst_prefix_dir data into the link command. + relink_command=`$echo "$relink_command" | $SP2NL | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%" | $NL2SP` + else + relink_command=`$echo "$relink_command" | $SP2NL | $SED "s%@inst_prefix_dir@%%" | $NL2SP` + fi + + $echo "$modename: warning: relinking \`$file'" 1>&2 + $show "$relink_command" + if $run eval "$relink_command"; then : + else + $echo "$modename: error: relink \`$file' with the above command before installing it" 1>&2 + exit $EXIT_FAILURE + fi + fi + + # See the names of the shared library. + set dummy $library_names + if test -n "$2"; then + realname="$2" + shift + shift + + srcname="$realname" + test -n "$relink_command" && srcname="$realname"T + + # Install the shared library and build the symlinks. + $show "$install_prog $dir/$srcname $destdir/$realname" + $run eval "$install_prog $dir/$srcname $destdir/$realname" || exit $? + if test -n "$stripme" && test -n "$striplib"; then + $show "$striplib $destdir/$realname" + $run eval "$striplib $destdir/$realname" || exit $? + fi + + if test "$#" -gt 0; then + # Delete the old symlinks, and create new ones. + # Try `ln -sf' first, because the `ln' binary might depend on + # the symlink we replace! Solaris /bin/ln does not understand -f, + # so we also need to try rm && ln -s. + for linkname + do + if test "$linkname" != "$realname"; then + $show "(cd $destdir && { $LN_S -f $realname $linkname || { $rm $linkname && $LN_S $realname $linkname; }; })" + $run eval "(cd $destdir && { $LN_S -f $realname $linkname || { $rm $linkname && $LN_S $realname $linkname; }; })" + fi + done + fi + + # Do each command in the postinstall commands. + lib="$destdir/$realname" + cmds=$postinstall_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" || { + lt_exit=$? + + # Restore the uninstalled library and exit + if test "$mode" = relink; then + $run eval '(cd $output_objdir && $rm ${realname}T && $mv ${realname}U $realname)' + fi + + exit $lt_exit + } + done + IFS="$save_ifs" + fi + + # Install the pseudo-library for information purposes. + name=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + instname="$dir/$name"i + $show "$install_prog $instname $destdir/$name" + $run eval "$install_prog $instname $destdir/$name" || exit $? + + # Maybe install the static library, too. + test -n "$old_library" && staticlibs="$staticlibs $dir/$old_library" + ;; + + *.lo) + # Install (i.e. copy) a libtool object. + + # Figure out destination file name, if it wasn't already specified. + if test -n "$destname"; then + destfile="$destdir/$destname" + else + destfile=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + destfile="$destdir/$destfile" + fi + + # Deduce the name of the destination old-style object file. + case $destfile in + *.lo) + staticdest=`$echo "X$destfile" | $Xsed -e "$lo2o"` + ;; + *.$objext) + staticdest="$destfile" + destfile= + ;; + *) + $echo "$modename: cannot copy a libtool object to \`$destfile'" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + ;; + esac + + # Install the libtool object if requested. + if test -n "$destfile"; then + $show "$install_prog $file $destfile" + $run eval "$install_prog $file $destfile" || exit $? + fi + + # Install the old object if enabled. + if test "$build_old_libs" = yes; then + # Deduce the name of the old-style object file. + staticobj=`$echo "X$file" | $Xsed -e "$lo2o"` + + $show "$install_prog $staticobj $staticdest" + $run eval "$install_prog \$staticobj \$staticdest" || exit $? + fi + exit $EXIT_SUCCESS + ;; + + *) + # Figure out destination file name, if it wasn't already specified. + if test -n "$destname"; then + destfile="$destdir/$destname" + else + destfile=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + destfile="$destdir/$destfile" + fi + + # If the file is missing, and there is a .exe on the end, strip it + # because it is most likely a libtool script we actually want to + # install + stripped_ext="" + case $file in + *.exe) + if test ! -f "$file"; then + file=`$echo $file|${SED} 's,.exe$,,'` + stripped_ext=".exe" + fi + ;; + esac + + # Do a test to see if this is really a libtool program. + case $host in + *cygwin*|*mingw*) + wrapper=`$echo $file | ${SED} -e 's,.exe$,,'` + ;; + *) + wrapper=$file + ;; + esac + if (${SED} -e '4q' $wrapper | grep "^# Generated by .*$PACKAGE")>/dev/null 2>&1; then + notinst_deplibs= + relink_command= + + # Note that it is not necessary on cygwin/mingw to append a dot to + # foo even if both foo and FILE.exe exist: automatic-append-.exe + # behavior happens only for exec(3), not for open(2)! Also, sourcing + # `FILE.' does not work on cygwin managed mounts. + # + # If there is no directory component, then add one. + case $wrapper in + */* | *\\*) . ${wrapper} ;; + *) . ./${wrapper} ;; + esac + + # Check the variables that should have been set. + if test -z "$notinst_deplibs"; then + $echo "$modename: invalid libtool wrapper script \`$wrapper'" 1>&2 + exit $EXIT_FAILURE + fi + + finalize=yes + for lib in $notinst_deplibs; do + # Check to see that each library is installed. + libdir= + if test -f "$lib"; then + # If there is no directory component, then add one. + case $lib in + */* | *\\*) . $lib ;; + *) . ./$lib ;; + esac + fi + libfile="$libdir/"`$echo "X$lib" | $Xsed -e 's%^.*/%%g'` ### testsuite: skip nested quoting test + if test -n "$libdir" && test ! -f "$libfile"; then + $echo "$modename: warning: \`$lib' has not been installed in \`$libdir'" 1>&2 + finalize=no + fi + done + + relink_command= + # Note that it is not necessary on cygwin/mingw to append a dot to + # foo even if both foo and FILE.exe exist: automatic-append-.exe + # behavior happens only for exec(3), not for open(2)! Also, sourcing + # `FILE.' does not work on cygwin managed mounts. + # + # If there is no directory component, then add one. + case $wrapper in + */* | *\\*) . ${wrapper} ;; + *) . ./${wrapper} ;; + esac + + outputname= + if test "$fast_install" = no && test -n "$relink_command"; then + if test "$finalize" = yes && test -z "$run"; then + tmpdir=`func_mktempdir` + file=`$echo "X$file$stripped_ext" | $Xsed -e 's%^.*/%%'` + outputname="$tmpdir/$file" + # Replace the output file specification. + relink_command=`$echo "X$relink_command" | $SP2NL | $Xsed -e 's%@OUTPUT@%'"$outputname"'%g' | $NL2SP` + + $show "$relink_command" + if $run eval "$relink_command"; then : + else + $echo "$modename: error: relink \`$file' with the above command before installing it" 1>&2 + ${rm}r "$tmpdir" + continue + fi + file="$outputname" + else + $echo "$modename: warning: cannot relink \`$file'" 1>&2 + fi + else + # Install the binary that we compiled earlier. + file=`$echo "X$file$stripped_ext" | $Xsed -e "s%\([^/]*\)$%$objdir/\1%"` + fi + fi + + # remove .exe since cygwin /usr/bin/install will append another + # one anyway + case $install_prog,$host in + */usr/bin/install*,*cygwin*) + case $file:$destfile in + *.exe:*.exe) + # this is ok + ;; + *.exe:*) + destfile=$destfile.exe + ;; + *:*.exe) + destfile=`$echo $destfile | ${SED} -e 's,.exe$,,'` + ;; + esac + ;; + esac + $show "$install_prog$stripme $file $destfile" + $run eval "$install_prog\$stripme \$file \$destfile" || exit $? + test -n "$outputname" && ${rm}r "$tmpdir" + ;; + esac + done + + for file in $staticlibs; do + name=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + + # Set up the ranlib parameters. + oldlib="$destdir/$name" + + $show "$install_prog $file $oldlib" + $run eval "$install_prog \$file \$oldlib" || exit $? + + if test -n "$stripme" && test -n "$old_striplib"; then + $show "$old_striplib $oldlib" + $run eval "$old_striplib $oldlib" || exit $? + fi + + # Do each command in the postinstall commands. + cmds=$old_postinstall_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + done + + if test -n "$future_libdirs"; then + $echo "$modename: warning: remember to run \`$progname --finish$future_libdirs'" 1>&2 + fi + + if test -n "$current_libdirs"; then + # Maybe just do a dry run. + test -n "$run" && current_libdirs=" -n$current_libdirs" + exec_cmd='$SHELL $progpath $preserve_args --finish$current_libdirs' + else + exit $EXIT_SUCCESS + fi + ;; + + # libtool finish mode + finish) + modename="$modename: finish" + libdirs="$nonopt" + admincmds= + + if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then + for dir + do + libdirs="$libdirs $dir" + done + + for libdir in $libdirs; do + if test -n "$finish_cmds"; then + # Do each command in the finish commands. + cmds=$finish_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" || admincmds="$admincmds + $cmd" + done + IFS="$save_ifs" + fi + if test -n "$finish_eval"; then + # Do the single finish_eval. + eval cmds=\"$finish_eval\" + $run eval "$cmds" || admincmds="$admincmds + $cmds" + fi + done + fi + + # Exit here if they wanted silent mode. + test "$show" = : && exit $EXIT_SUCCESS + + $echo "X----------------------------------------------------------------------" | $Xsed + $echo "Libraries have been installed in:" + for libdir in $libdirs; do + $echo " $libdir" + done + $echo + $echo "If you ever happen to want to link against installed libraries" + $echo "in a given directory, LIBDIR, you must either use libtool, and" + $echo "specify the full pathname of the library, or use the \`-LLIBDIR'" + $echo "flag during linking and do at least one of the following:" + if test -n "$shlibpath_var"; then + $echo " - add LIBDIR to the \`$shlibpath_var' environment variable" + $echo " during execution" + fi + if test -n "$runpath_var"; then + $echo " - add LIBDIR to the \`$runpath_var' environment variable" + $echo " during linking" + fi + if test -n "$hardcode_libdir_flag_spec"; then + libdir=LIBDIR + eval flag=\"$hardcode_libdir_flag_spec\" + + $echo " - use the \`$flag' linker flag" + fi + if test -n "$admincmds"; then + $echo " - have your system administrator run these commands:$admincmds" + fi + if test -f /etc/ld.so.conf; then + $echo " - have your system administrator add LIBDIR to \`/etc/ld.so.conf'" + fi + $echo + $echo "See any operating system documentation about shared libraries for" + $echo "more information, such as the ld(1) and ld.so(8) manual pages." + $echo "X----------------------------------------------------------------------" | $Xsed + exit $EXIT_SUCCESS + ;; + + # libtool execute mode + execute) + modename="$modename: execute" + + # The first argument is the command name. + cmd="$nonopt" + if test -z "$cmd"; then + $echo "$modename: you must specify a COMMAND" 1>&2 + $echo "$help" + exit $EXIT_FAILURE + fi + + # Handle -dlopen flags immediately. + for file in $execute_dlfiles; do + if test ! -f "$file"; then + $echo "$modename: \`$file' is not a file" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + dir= + case $file in + *.la) + # Check to see that this really is a libtool archive. + if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then : + else + $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + # Read the libtool library. + dlname= + library_names= + + # If there is no directory component, then add one. + case $file in + */* | *\\*) . $file ;; + *) . ./$file ;; + esac + + # Skip this library if it cannot be dlopened. + if test -z "$dlname"; then + # Warn if it was a shared library. + test -n "$library_names" && $echo "$modename: warning: \`$file' was not linked with \`-export-dynamic'" + continue + fi + + dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'` + test "X$dir" = "X$file" && dir=. + + if test -f "$dir/$objdir/$dlname"; then + dir="$dir/$objdir" + else + if test ! -f "$dir/$dlname"; then + $echo "$modename: cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'" 1>&2 + exit $EXIT_FAILURE + fi + fi + ;; + + *.lo) + # Just add the directory containing the .lo file. + dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'` + test "X$dir" = "X$file" && dir=. + ;; + + *) + $echo "$modename: warning \`-dlopen' is ignored for non-libtool libraries and objects" 1>&2 + continue + ;; + esac + + # Get the absolute pathname. + absdir=`cd "$dir" && pwd` + test -n "$absdir" && dir="$absdir" + + # Now add the directory to shlibpath_var. + if eval "test -z \"\$$shlibpath_var\""; then + eval "$shlibpath_var=\"\$dir\"" + else + eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\"" + fi + done + + # This variable tells wrapper scripts just to set shlibpath_var + # rather than running their programs. + libtool_execute_magic="$magic" + + # Check if any of the arguments is a wrapper script. + args= + for file + do + case $file in + -*) ;; + *) + # Do a test to see if this is really a libtool program. + if (${SED} -e '4q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + # If there is no directory component, then add one. + case $file in + */* | *\\*) . $file ;; + *) . ./$file ;; + esac + + # Transform arg to wrapped name. + file="$progdir/$program" + fi + ;; + esac + # Quote arguments (to preserve shell metacharacters). + file=`$echo "X$file" | $Xsed -e "$sed_quote_subst"` + args="$args \"$file\"" + done + + if test -z "$run"; then + if test -n "$shlibpath_var"; then + # Export the shlibpath_var. + eval "export $shlibpath_var" + fi + + # Restore saved environment variables + for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES + do + eval "if test \"\${save_$lt_var+set}\" = set; then + $lt_var=\$save_$lt_var; export $lt_var + fi" + done + + # Now prepare to actually exec the command. + exec_cmd="\$cmd$args" + else + # Display what would be done. + if test -n "$shlibpath_var"; then + eval "\$echo \"\$shlibpath_var=\$$shlibpath_var\"" + $echo "export $shlibpath_var" + fi + $echo "$cmd$args" + exit $EXIT_SUCCESS + fi + ;; + + # libtool clean and uninstall mode + clean | uninstall) + modename="$modename: $mode" + rm="$nonopt" + files= + rmforce= + exit_status=0 + + # This variable tells wrapper scripts just to set variables rather + # than running their programs. + libtool_install_magic="$magic" + + for arg + do + case $arg in + -f) rm="$rm $arg"; rmforce=yes ;; + -*) rm="$rm $arg" ;; + *) files="$files $arg" ;; + esac + done + + if test -z "$rm"; then + $echo "$modename: you must specify an RM program" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + rmdirs= + + origobjdir="$objdir" + for file in $files; do + dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'` + if test "X$dir" = "X$file"; then + dir=. + objdir="$origobjdir" + else + objdir="$dir/$origobjdir" + fi + name=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + test "$mode" = uninstall && objdir="$dir" + + # Remember objdir for removal later, being careful to avoid duplicates + if test "$mode" = clean; then + case " $rmdirs " in + *" $objdir "*) ;; + *) rmdirs="$rmdirs $objdir" ;; + esac + fi + + # Don't error if the file doesn't exist and rm -f was used. + if (test -L "$file") >/dev/null 2>&1 \ + || (test -h "$file") >/dev/null 2>&1 \ + || test -f "$file"; then + : + elif test -d "$file"; then + exit_status=1 + continue + elif test "$rmforce" = yes; then + continue + fi + + rmfiles="$file" + + case $name in + *.la) + # Possibly a libtool archive, so verify it. + if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + . $dir/$name + + # Delete the libtool libraries and symlinks. + for n in $library_names; do + rmfiles="$rmfiles $objdir/$n" + done + test -n "$old_library" && rmfiles="$rmfiles $objdir/$old_library" + + case "$mode" in + clean) + case " $library_names " in + # " " in the beginning catches empty $dlname + *" $dlname "*) ;; + *) rmfiles="$rmfiles $objdir/$dlname" ;; + esac + test -n "$libdir" && rmfiles="$rmfiles $objdir/$name $objdir/${name}i" + ;; + uninstall) + if test -n "$library_names"; then + # Do each command in the postuninstall commands. + cmds=$postuninstall_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" + if test "$?" -ne 0 && test "$rmforce" != yes; then + exit_status=1 + fi + done + IFS="$save_ifs" + fi + + if test -n "$old_library"; then + # Do each command in the old_postuninstall commands. + cmds=$old_postuninstall_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" + if test "$?" -ne 0 && test "$rmforce" != yes; then + exit_status=1 + fi + done + IFS="$save_ifs" + fi + # FIXME: should reinstall the best remaining shared library. + ;; + esac + fi + ;; + + *.lo) + # Possibly a libtool object, so verify it. + if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + + # Read the .lo file + . $dir/$name + + # Add PIC object to the list of files to remove. + if test -n "$pic_object" \ + && test "$pic_object" != none; then + rmfiles="$rmfiles $dir/$pic_object" + fi + + # Add non-PIC object to the list of files to remove. + if test -n "$non_pic_object" \ + && test "$non_pic_object" != none; then + rmfiles="$rmfiles $dir/$non_pic_object" + fi + fi + ;; + + *) + if test "$mode" = clean ; then + noexename=$name + case $file in + *.exe) + file=`$echo $file|${SED} 's,.exe$,,'` + noexename=`$echo $name|${SED} 's,.exe$,,'` + # $file with .exe has already been added to rmfiles, + # add $file without .exe + rmfiles="$rmfiles $file" + ;; + esac + # Do a test to see if this is a libtool program. + if (${SED} -e '4q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + relink_command= + . $dir/$noexename + + # note $name still contains .exe if it was in $file originally + # as does the version of $file that was added into $rmfiles + rmfiles="$rmfiles $objdir/$name $objdir/${name}S.${objext}" + if test "$fast_install" = yes && test -n "$relink_command"; then + rmfiles="$rmfiles $objdir/lt-$name" + fi + if test "X$noexename" != "X$name" ; then + rmfiles="$rmfiles $objdir/lt-${noexename}.c" + fi + fi + fi + ;; + esac + $show "$rm $rmfiles" + $run $rm $rmfiles || exit_status=1 + done + objdir="$origobjdir" + + # Try to remove the ${objdir}s in the directories where we deleted files + for dir in $rmdirs; do + if test -d "$dir"; then + $show "rmdir $dir" + $run rmdir $dir >/dev/null 2>&1 + fi + done + + exit $exit_status + ;; + + "") + $echo "$modename: you must specify a MODE" 1>&2 + $echo "$generic_help" 1>&2 + exit $EXIT_FAILURE + ;; + esac + + if test -z "$exec_cmd"; then + $echo "$modename: invalid operation mode \`$mode'" 1>&2 + $echo "$generic_help" 1>&2 + exit $EXIT_FAILURE + fi +fi # test -z "$show_help" + +if test -n "$exec_cmd"; then + eval exec $exec_cmd + exit $EXIT_FAILURE +fi + +# We need to display help for each of the modes. +case $mode in +"") $echo \ +"Usage: $modename [OPTION]... [MODE-ARG]... + +Provide generalized library-building support services. + + --config show all configuration variables + --debug enable verbose shell tracing +-n, --dry-run display commands without modifying any files + --features display basic configuration information and exit + --finish same as \`--mode=finish' + --help display this help message and exit + --mode=MODE use operation mode MODE [default=inferred from MODE-ARGS] + --quiet same as \`--silent' + --silent don't print informational messages + --tag=TAG use configuration variables from tag TAG + --version print version information + +MODE must be one of the following: + + clean remove files from the build directory + compile compile a source file into a libtool object + execute automatically set library path, then run a program + finish complete the installation of libtool libraries + install install libraries or executables + link create a library or an executable + uninstall remove libraries from an installed directory + +MODE-ARGS vary depending on the MODE. Try \`$modename --help --mode=MODE' for +a more detailed description of MODE. + +Report bugs to ." + exit $EXIT_SUCCESS + ;; + +clean) + $echo \ +"Usage: $modename [OPTION]... --mode=clean RM [RM-OPTION]... FILE... + +Remove files from the build directory. + +RM is the name of the program to use to delete files associated with each FILE +(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed +to RM. + +If FILE is a libtool library, object or program, all the files associated +with it are deleted. Otherwise, only FILE itself is deleted using RM." + ;; + +compile) + $echo \ +"Usage: $modename [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE + +Compile a source file into a libtool library object. + +This mode accepts the following additional options: + + -o OUTPUT-FILE set the output file name to OUTPUT-FILE + -prefer-pic try to building PIC objects only + -prefer-non-pic try to building non-PIC objects only + -static always build a \`.o' file suitable for static linking + +COMPILE-COMMAND is a command to be used in creating a \`standard' object file +from the given SOURCEFILE. + +The output file name is determined by removing the directory component from +SOURCEFILE, then substituting the C source code suffix \`.c' with the +library object suffix, \`.lo'." + ;; + +execute) + $echo \ +"Usage: $modename [OPTION]... --mode=execute COMMAND [ARGS]... + +Automatically set library path, then run a program. + +This mode accepts the following additional options: + + -dlopen FILE add the directory containing FILE to the library path + +This mode sets the library path environment variable according to \`-dlopen' +flags. + +If any of the ARGS are libtool executable wrappers, then they are translated +into their corresponding uninstalled binary, and any of their required library +directories are added to the library path. + +Then, COMMAND is executed, with ARGS as arguments." + ;; + +finish) + $echo \ +"Usage: $modename [OPTION]... --mode=finish [LIBDIR]... + +Complete the installation of libtool libraries. + +Each LIBDIR is a directory that contains libtool libraries. + +The commands that this mode executes may require superuser privileges. Use +the \`--dry-run' option if you just want to see what would be executed." + ;; + +install) + $echo \ +"Usage: $modename [OPTION]... --mode=install INSTALL-COMMAND... + +Install executables or libraries. + +INSTALL-COMMAND is the installation command. The first component should be +either the \`install' or \`cp' program. + +The rest of the components are interpreted as arguments to that command (only +BSD-compatible install options are recognized)." + ;; + +link) + $echo \ +"Usage: $modename [OPTION]... --mode=link LINK-COMMAND... + +Link object files or libraries together to form another library, or to +create an executable program. + +LINK-COMMAND is a command using the C compiler that you would use to create +a program from several object files. + +The following components of LINK-COMMAND are treated specially: + + -all-static do not do any dynamic linking at all + -avoid-version do not add a version suffix if possible + -dlopen FILE \`-dlpreopen' FILE if it cannot be dlopened at runtime + -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols + -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3) + -export-symbols SYMFILE + try to export only the symbols listed in SYMFILE + -export-symbols-regex REGEX + try to export only the symbols matching REGEX + -LLIBDIR search LIBDIR for required installed libraries + -lNAME OUTPUT-FILE requires the installed library libNAME + -module build a library that can dlopened + -no-fast-install disable the fast-install mode + -no-install link a not-installable executable + -no-undefined declare that a library does not refer to external symbols + -o OUTPUT-FILE create OUTPUT-FILE from the specified objects + -objectlist FILE Use a list of object files found in FILE to specify objects + -precious-files-regex REGEX + don't remove output files matching REGEX + -release RELEASE specify package release information + -rpath LIBDIR the created library will eventually be installed in LIBDIR + -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries + -static do not do any dynamic linking of uninstalled libtool libraries + -static-libtool-libs + do not do any dynamic linking of libtool libraries + -version-info CURRENT[:REVISION[:AGE]] + specify library version info [each variable defaults to 0] + +All other options (arguments beginning with \`-') are ignored. + +Every other argument is treated as a filename. Files ending in \`.la' are +treated as uninstalled libtool libraries, other files are standard or library +object files. + +If the OUTPUT-FILE ends in \`.la', then a libtool library is created, +only library objects (\`.lo' files) may be specified, and \`-rpath' is +required, except when creating a convenience library. + +If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created +using \`ar' and \`ranlib', or on Windows using \`lib'. + +If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file +is created, otherwise an executable program is created." + ;; + +uninstall) + $echo \ +"Usage: $modename [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE... + +Remove libraries from an installation directory. + +RM is the name of the program to use to delete files associated with each FILE +(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed +to RM. + +If FILE is a libtool library, all the files associated with it are deleted. +Otherwise, only FILE itself is deleted using RM." + ;; + +*) + $echo "$modename: invalid operation mode \`$mode'" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + ;; +esac + +$echo +$echo "Try \`$modename --help' for more information about other modes." + +exit $? + +# The TAGs below are defined such that we never get into a situation +# in which we disable both kinds of libraries. Given conflicting +# choices, we go for a static library, that is the most portable, +# since we can't tell whether shared libraries were disabled because +# the user asked for that or because the platform doesn't support +# them. This is particularly important on AIX, because we don't +# support having both static and shared libraries enabled at the same +# time on that platform, so we default to a shared-only configuration. +# If a disable-shared tag is given, we'll fallback to a static-only +# configuration. But we'll never go from static-only to shared-only. + +# ### BEGIN LIBTOOL TAG CONFIG: disable-shared +disable_libs=shared +# ### END LIBTOOL TAG CONFIG: disable-shared + +# ### BEGIN LIBTOOL TAG CONFIG: disable-static +disable_libs=static +# ### END LIBTOOL TAG CONFIG: disable-static + +# Local Variables: +# mode:shell-script +# sh-indentation:2 +# End: diff --git a/m4/.keep b/m4/.keep new file mode 100755 index 0000000..e69de29 --- a/dev/null +++ b/m4/.keep diff --git a/missing b/missing new file mode 100755 index 0000000..1c8ff70 --- a/dev/null +++ b/missing @@ -0,0 +1,367 @@ +#! /bin/sh +# Common stub for a few missing GNU programs while installing. + +scriptversion=2006-05-10.23 + +# Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005, 2006 +# Free Software Foundation, Inc. +# Originally 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, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + +# 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 + +run=: +sed_output='s/.* --output[ =]\([^ ]*\).*/\1/p' +sed_minuso='s/.* -o \([^ ]*\).*/\1/p' + +# In the cases where this matters, `missing' is being run in the +# srcdir already. +if test -f configure.ac; then + configure_ac=configure.ac +else + configure_ac=configure.in +fi + +msg="missing on your system" + +case $1 in +--run) + # Try to run requested program, and just exit if it succeeds. + run= + shift + "$@" && exit 0 + # Exit code 63 means version mismatch. This often happens + # when the user try to use an ancient version of a tool on + # a file that requires a minimum version. In this case we + # we should proceed has if the program had been absent, or + # if --run hadn't been passed. + if test $? = 63; then + run=: + msg="probably too old" + fi + ;; + + -h|--h|--he|--hel|--help) + echo "\ +$0 [OPTION]... PROGRAM [ARGUMENT]... + +Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an +error status if there is no known handling for PROGRAM. + +Options: + -h, --help display this help and exit + -v, --version output version information and exit + --run try to run the given command, and emulate it if it fails + +Supported PROGRAM values: + aclocal touch file \`aclocal.m4' + autoconf touch file \`configure' + autoheader touch file \`config.h.in' + autom4te touch the output file, or create a stub one + automake touch all \`Makefile.in' files + bison create \`y.tab.[ch]', if possible, from existing .[ch] + flex create \`lex.yy.c', if possible, from existing .c + help2man touch the output file + lex create \`lex.yy.c', if possible, from existing .c + makeinfo touch the output file + tar try tar, gnutar, gtar, then tar without non-portable flags + yacc create \`y.tab.[ch]', if possible, from existing .[ch] + +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 + +# Now exit if we have it, but it failed. Also exit now if we +# don't have it and --version was passed (most likely to detect +# the program). +case $1 in + lex|yacc) + # Not GNU programs, they don't have --version. + ;; + + tar) + if test -n "$run"; then + echo 1>&2 "ERROR: \`tar' requires --run" + exit 1 + elif test "x$2" = "x--version" || test "x$2" = "x--help"; then + exit 1 + fi + ;; + + *) + if test -z "$run" && ($1 --version) > /dev/null 2>&1; then + # We have it, but it failed. + exit 1 + elif test "x$2" = "x--version" || test "x$2" = "x--help"; then + # Could not run --version or --help. This is probably someone + # running `$TOOL --version' or `$TOOL --help' to check whether + # $TOOL exists and not knowing $TOOL uses missing. + exit 1 + fi + ;; +esac + +# If it does not exist, or fails to run (possibly an outdated version), +# try to emulate it. +case $1 in + aclocal*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`acinclude.m4' or \`${configure_ac}'. You might want + to install the \`Automake' and \`Perl' packages. Grab them from + any GNU archive site." + touch aclocal.m4 + ;; + + autoconf) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`${configure_ac}'. You might want to install the + \`Autoconf' and \`GNU m4' packages. Grab them from any GNU + archive site." + touch configure + ;; + + autoheader) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`acconfig.h' or \`${configure_ac}'. You might want + to install the \`Autoconf' and \`GNU m4' packages. Grab them + from any GNU archive site." + files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}` + test -z "$files" && files="config.h" + touch_files= + for f in $files; do + case $f in + *:*) touch_files="$touch_files "`echo "$f" | + sed -e 's/^[^:]*://' -e 's/:.*//'`;; + *) touch_files="$touch_files $f.in";; + esac + done + touch $touch_files + ;; + + automake*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'. + You might want to install the \`Automake' and \`Perl' packages. + Grab them from any GNU archive site." + find . -type f -name Makefile.am -print | + sed 's/\.am$/.in/' | + while read f; do touch "$f"; done + ;; + + autom4te) + echo 1>&2 "\ +WARNING: \`$1' is needed, but is $msg. + You might have modified some files without having the + proper tools for further handling them. + You can get \`$1' as part of \`Autoconf' from any GNU + archive site." + + file=`echo "$*" | sed -n "$sed_output"` + test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` + if test -f "$file"; then + touch $file + else + test -z "$file" || exec >$file + echo "#! /bin/sh" + echo "# Created by GNU Automake missing as a replacement of" + echo "# $ $@" + echo "exit 0" + chmod +x $file + exit 1 + fi + ;; + + bison|yacc) + echo 1>&2 "\ +WARNING: \`$1' $msg. You should only need it if + you modified a \`.y' file. You may need the \`Bison' package + in order for those modifications to take effect. You can get + \`Bison' from any GNU archive site." + rm -f y.tab.c y.tab.h + if test $# -ne 1; then + eval LASTARG="\${$#}" + case $LASTARG in + *.y) + SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'` + if test -f "$SRCFILE"; then + cp "$SRCFILE" y.tab.c + fi + SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'` + if test -f "$SRCFILE"; then + cp "$SRCFILE" y.tab.h + fi + ;; + esac + fi + if test ! -f y.tab.h; then + echo >y.tab.h + fi + if test ! -f y.tab.c; then + echo 'main() { return 0; }' >y.tab.c + fi + ;; + + lex|flex) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified a \`.l' file. You may need the \`Flex' package + in order for those modifications to take effect. You can get + \`Flex' from any GNU archive site." + rm -f lex.yy.c + if test $# -ne 1; then + eval LASTARG="\${$#}" + case $LASTARG in + *.l) + SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'` + if test -f "$SRCFILE"; then + cp "$SRCFILE" lex.yy.c + fi + ;; + esac + fi + if test ! -f lex.yy.c; then + echo 'main() { return 0; }' >lex.yy.c + fi + ;; + + help2man) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified a dependency of a manual page. You may need the + \`Help2man' package in order for those modifications to take + effect. You can get \`Help2man' from any GNU archive site." + + file=`echo "$*" | sed -n "$sed_output"` + test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` + if test -f "$file"; then + touch $file + else + test -z "$file" || exec >$file + echo ".ab help2man is required to generate this page" + exit 1 + fi + ;; + + makeinfo) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified a \`.texi' or \`.texinfo' file, or any other file + indirectly affecting the aspect of the manual. The spurious + call might also be the consequence of using a buggy \`make' (AIX, + DU, IRIX). You might want to install the \`Texinfo' package or + the \`GNU make' package. Grab either from any GNU archive site." + # The file to touch is that specified with -o ... + file=`echo "$*" | sed -n "$sed_output"` + test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` + if test -z "$file"; then + # ... or it is the one specified with @setfilename ... + infile=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'` + file=`sed -n ' + /^@setfilename/{ + s/.* \([^ ]*\) *$/\1/ + p + q + }' $infile` + # ... or it is derived from the source name (dir/f.texi becomes f.info) + test -z "$file" && file=`echo "$infile" | sed 's,.*/,,;s,.[^.]*$,,'`.info + fi + # If the file does not exist, the user really needs makeinfo; + # let's fail without touching anything. + test -f $file || exit 1 + touch $file + ;; + + tar) + shift + + # We have already tried tar in the generic part. + # Look for gnutar/gtar before invocation to avoid ugly error + # messages. + if (gnutar --version > /dev/null 2>&1); then + gnutar "$@" && exit 0 + fi + if (gtar --version > /dev/null 2>&1); then + gtar "$@" && exit 0 + fi + firstarg="$1" + if shift; then + case $firstarg in + *o*) + firstarg=`echo "$firstarg" | sed s/o//` + tar "$firstarg" "$@" && exit 0 + ;; + esac + case $firstarg in + *h*) + firstarg=`echo "$firstarg" | sed s/h//` + tar "$firstarg" "$@" && exit 0 + ;; + esac + fi + + echo 1>&2 "\ +WARNING: I can't seem to be able to run \`tar' with the given arguments. + You may want to install GNU tar or Free paxutils, or check the + command line arguments." + exit 1 + ;; + + *) + echo 1>&2 "\ +WARNING: \`$1' is needed, and is $msg. + You might have modified some files without having the + proper tools for further handling them. Check the \`README' file, + it often tells you about the needed prerequisites for installing + this package. You may also peek at any GNU archive site, in case + some other package would contain this missing \`$1' program." + exit 1 + ;; +esac + +exit 0 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-end: "$" +# End: diff --git a/prog.IAB b/prog.IAB new file mode 100755 index 0000000..167d18e --- a/dev/null +++ b/prog.IAB @@ -0,0 +1,1071 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +6 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ( + + + + + + + +B + +/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +6 + + + + + + + + + ( + + + + + + + + + + + +B + + + + + + + + + + + + + + + + + + + + + + ( + + + + + + + + + + + + + + + + + + + + + + + + + +C + + + + + + + + + + +6 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +' +B + +/ +' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +C +6 + + + + + + + +' +' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +C + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +C + + + + + + + + + + + ( + + + + + + + + + + +B + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +6 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/prog.IAD b/prog.IAD new file mode 100755 index 0000000..3329394 --- a/dev/null +++ b/prog.IAD @@ -0,0 +1,5 @@ +’ + + + + diff --git a/prog.IMB b/prog.IMB new file mode 100755 index 0000000..1c9c978 --- a/dev/null +++ b/prog.IMB @@ -0,0 +1,466 @@ +Ÿ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +C + + + + + + + + + + + + + +B + + + + + +/ + + + + + + + + + + + + + + + + + + + + + + + + + + +' +' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +6 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +C + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +' +' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/prog.IMD b/prog.IMD new file mode 100755 index 0000000..d71a53c --- a/dev/null +++ b/prog.IMD @@ -0,0 +1,2 @@ +’ + diff --git a/prog.PFI b/prog.PFI new file mode 100755 index 0000000..51211ed --- a/dev/null +++ b/prog.PFI @@ -0,0 +1,2 @@ + + diff --git a/prog.PO b/prog.PO new file mode 100755 index 0000000..666d349 --- a/dev/null +++ b/prog.PO @@ -0,0 +1 @@ +1 diff --git a/prog.PR b/prog.PR new file mode 100755 index 0000000..c3bd870 --- a/dev/null +++ b/prog.PR @@ -0,0 +1,14 @@ +# + + + + + +# + + + + + + + diff --git a/prog.PRI b/prog.PRI new file mode 100755 index 0000000..6ab7b84 --- a/dev/null +++ b/prog.PRI @@ -0,0 +1,219 @@ + +@ + + +}­D:z7¥ËÞ¨v%§Šg¥[X”€Â + + +b8 +IA +!H  +  + +@ +P +@ + %„Aä"` + @  + +H¡ L + +„ + + + +0H  +X$ + +  + +€ + 2€°  aƒ(Qa` + + + +”  + +% + + „H @@  + + + + + + +2 +„Hb + + +€¢™@3 †@BR + + +` + + + + +($¦Ñ¸—éEáZ‘@ + +@ + +  +@))à + Ñ° ` €PAA + + µÓô"é + +@2€ A" + + +! + +²,‘ÌÂ"X%€1LIú‰> ð””Âf‰"à "B* + +0b’´ x—óù‚Ä{9«¾Kã6l  + +Ð +„ + +€ + + +$ + + +@ + + +@ + + + +! +²,±ÌÂ"x%€qLAø‰> ð”Âf‰Ã("B( +0¢’· x—óùÀÄ{9«¾Kc>o  + +Ð +„ + + +` + + +$ + +$ ‚ +€ + +$ + f„A¢Á&$¡ P@„ +  @ +"B@ +@ +yÿöïoÎa¥}R@€ +EQº#-E + +° $0Π +L,ÕL²}à¡j@=”) +@b + + +0 DÔ +P + + ( + + + +@@ + + + +‚ + +iÚo¯gÄI Eä +("%¥$!J + +@H + +€ + + +€ +@@ +EH "R@ +€ +* +@ + +@á  + + + +Q” A ‚ +a + B + + + + + +‚ +hõæíCÆé]%L +‚Ž€: õ„¶D â +0ÉaL† $ +ðP * + + +@ + + +( + ÃÀ" 2ã€P@€ ( + +@ + + + +’ (' + +  ƒ + +HX G‡d`‚ + +”"j± + +”(TÇ‘”za + +H# †€ˆ€ +@ð + + + + ‚€P@ +Bˆ + ÁŽ À + " +D@ +@@ +†H +B…@2c!› +#include + +#if !defined(FUSE_VERSION) || (FUSE_VERSION < 26) +#error "***********************************************************" +#error "* *" +#error "* Compilation requires at least FUSE version 2.6.0! *" +#error "* *" +#error "***********************************************************" +#endif + +#ifdef FUSE_INTERNAL +#define FUSE_TYPE "integrated FUSE low" +#else +#define FUSE_TYPE "external FUSE low" +#endif + +#ifdef HAVE_STDIO_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_ERRNO_H +#include +#endif +#ifdef HAVE_FCNTL_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_LOCALE_H +#include +#endif +#include +#ifdef HAVE_LIMITS_H +#include +#endif +#include +#include +#include + +#ifdef HAVE_SETXATTR +#include +#endif + +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_MKDEV_H +#include +#endif + +#if defined(__APPLE__) || defined(__DARWIN__) +#include +#endif /* defined(__APPLE__) || defined(__DARWIN__) */ + +#include "compat.h" +#include "attrib.h" +#include "inode.h" +#include "volume.h" +#include "dir.h" +#include "unistr.h" +#include "layout.h" +#include "index.h" +#include "ntfstime.h" +#include "security.h" +#include "reparse.h" +#include "object_id.h" +#include "efs.h" +#include "logging.h" +#include "misc.h" + +/* + * The following permission checking modes are governed by + * the LPERMSCONFIG value in param.h + */ + +/* ACLS may be checked by kernel (requires a fuse patch) or here */ +#define KERNELACLS ((LPERMSCONFIG > 6) & (LPERMSCONFIG < 10)) +/* basic permissions may be checked by kernel or here */ +#define KERNELPERMS (((LPERMSCONFIG - 1) % 6) < 3) +/* may want to use fuse/kernel cacheing */ +#define CACHEING (!(LPERMSCONFIG % 3)) + +#if KERNELACLS & !KERNELPERMS +#error "Incompatible options KERNELACLS and KERNELPERMS" +#endif + +#if CACHEING & (KERNELACLS | !KERNELPERMS) +#warning "Fuse cacheing is broken unless basic permissions checked by kernel" +#endif + +#if !CACHEING + /* + * FUSE cacheing is broken except for basic permissions + * checked by the kernel + * So do not use cacheing until this is fixed + */ +#define ATTR_TIMEOUT 0.0 +#define ENTRY_TIMEOUT 0.0 +#else +#define ATTR_TIMEOUT (ctx->vol->secure_flags & (1 << SECURITY_DEFAULT) ? 1.0 : 0.0) +#define ENTRY_TIMEOUT (ctx->vol->secure_flags & (1 << SECURITY_DEFAULT) ? 1.0 : 0.0) +#endif +#define GHOSTLTH 40 /* max length of a ghost file name - see ghostformat */ + + /* sometimes the kernel cannot check access */ +#define ntfs_real_allowed_access(scx, ni, type) ntfs_allowed_access(scx, ni, type) +#if POSIXACLS & KERNELPERMS & !KERNELACLS + /* short-circuit if PERMS checked by kernel and ACLs by fs */ +#define ntfs_allowed_access(scx, ni, type) \ + ((scx)->vol->secure_flags & (1 << SECURITY_DEFAULT) \ + ? 1 : ntfs_allowed_access(scx, ni, type)) +#endif + +#define set_archive(ni) (ni)->flags |= FILE_ATTR_ARCHIVE +#define INODE(ino) ((ino) == 1 ? (MFT_REF)FILE_root : (MFT_REF)(ino)) + +typedef enum { + FSTYPE_NONE, + FSTYPE_UNKNOWN, + FSTYPE_FUSE, + FSTYPE_FUSEBLK +} fuse_fstype; + +typedef enum { + ATIME_ENABLED, + ATIME_DISABLED, + ATIME_RELATIVE +} ntfs_atime_t; + +typedef struct fill_item { + struct fill_item *next; + size_t bufsize; + size_t off; + char buf[0]; +} ntfs_fuse_fill_item_t; + +typedef struct fill_context { + struct fill_item *first; + struct fill_item *last; + fuse_req_t req; + fuse_ino_t ino; + BOOL filled; +} ntfs_fuse_fill_context_t; + +struct open_file { + struct open_file *next; + struct open_file *previous; + long long ghost; + fuse_ino_t ino; + fuse_ino_t parent; + int state; +} ; + +typedef enum { + NF_STREAMS_INTERFACE_NONE, /* No access to named data streams. */ + NF_STREAMS_INTERFACE_XATTR, /* Map named data streams to xattrs. */ + NF_STREAMS_INTERFACE_OPENXATTR, /* Same, not limited to "user." */ +} ntfs_fuse_streams_interface; + +enum { + CLOSE_GHOST = 1, + CLOSE_COMPRESSED = 2, + CLOSE_ENCRYPTED = 4 +}; + +typedef struct { + ntfs_volume *vol; + unsigned int uid; + unsigned int gid; + unsigned int fmask; + unsigned int dmask; + ntfs_fuse_streams_interface streams; + ntfs_atime_t atime; + BOOL ro; + BOOL show_sys_files; + BOOL silent; + BOOL recover; + BOOL hiberfile; + BOOL debug; + BOOL no_detach; + BOOL blkdev; + BOOL mounted; +#ifdef HAVE_SETXATTR /* extended attributes interface required */ + BOOL efs_raw; +#endif /* HAVE_SETXATTR */ + struct fuse_chan *fc; + BOOL inherit; + unsigned int secure_flags; + char *usermap_path; + char *abs_mnt_point; + struct PERMISSIONS_CACHE *seccache; + struct SECURITY_CONTEXT security; + struct open_file *open_files; + u64 latest_ghost; +} ntfs_fuse_context_t; + +static struct options { + char *mnt_point; /* Mount point */ + char *options; /* Mount options */ + char *device; /* Device to mount */ +} opts; + +static const char *EXEC_NAME = "ntfs-3g"; +static char def_opts[] = "silent,allow_other,nonempty,"; +static ntfs_fuse_context_t *ctx; +static u32 ntfs_sequence; +static const char ghostformat[] = ".ghost-ntfs-3g-%020llu"; + +static const char *usage_msg = +"\n" +"%s %s %s %d - Third Generation NTFS Driver\n" +"\t\tConfiguration type %d, " +#ifdef HAVE_SETXATTR +"XATTRS are on, " +#else +"XATTRS are off, " +#endif +#if POSIXACLS +"POSIX ACLS are on\n" +#else +"POSIX ACLS are off\n" +#endif +"\n" +"Copyright (C) 2005-2007 Yura Pakhuchiy\n" +"Copyright (C) 2006-2009 Szabolcs Szakacsits\n" +"Copyright (C) 2007-2010 Jean-Pierre Andre\n" +"Copyright (C) 2009 Erik Larsson\n" +"\n" +"Usage: %s [-o option[,...]] \n" +"\n" +"Options: ro (read-only mount), remove_hiberfile, uid=, gid=,\n" +" umask=, fmask=, dmask=, streams_interface=.\n" +" Please see the details in the manual (type: man ntfs-3g).\n" +"\n" +"Example: ntfs-3g /dev/sda1 /mnt/windows\n" +"\n" +"%s"; + +static const char ntfs_bad_reparse[] = "unsupported reparse point"; + +#ifdef FUSE_INTERNAL +int drop_privs(void); +int restore_privs(void); +#else +/* + * setuid and setgid root ntfs-3g denies to start with external FUSE, + * therefore the below functions are no-op in such case. + */ +static int drop_privs(void) { return 0; } +#if defined(linux) || defined(__uClinux__) +static int restore_privs(void) { return 0; } +#endif + +static const char *setuid_msg = +"Mount is denied because setuid and setgid root ntfs-3g is insecure with the\n" +"external FUSE library. Either remove the setuid/setgid bit from the binary\n" +"or rebuild NTFS-3G with integrated FUSE support and make it setuid root.\n" +"Please see more information at http://ntfs-3g.org/support.html#unprivileged\n"; + +static const char *unpriv_fuseblk_msg = +"Unprivileged user can not mount NTFS block devices using the external FUSE\n" +"library. Either mount the volume as root, or rebuild NTFS-3G with integrated\n" +"FUSE support and make it setuid root. Please see more information at\n" +"http://ntfs-3g.org/support.html#unprivileged\n"; +#endif + + +static void ntfs_fuse_update_times(ntfs_inode *ni, ntfs_time_update_flags mask) +{ + if (ctx->atime == ATIME_DISABLED) + mask &= ~NTFS_UPDATE_ATIME; + else if (ctx->atime == ATIME_RELATIVE && mask == NTFS_UPDATE_ATIME && + (le64_to_cpu(ni->last_access_time) + >= le64_to_cpu(ni->last_data_change_time)) && + (le64_to_cpu(ni->last_access_time) + >= le64_to_cpu(ni->last_mft_change_time))) + return; + ntfs_inode_update_times(ni, mask); +} + +static s64 ntfs_get_nr_free_mft_records(ntfs_volume *vol) +{ + ntfs_attr *na = vol->mftbmp_na; + s64 nr_free = ntfs_attr_get_free_bits(na); + + if (nr_free >= 0) + nr_free += (na->allocated_size - na->data_size) << 3; + return nr_free; +} + +/* + * Fill a security context as needed by security functions + * returns TRUE if there is a user mapping, + * FALSE if there is none + * This is not an error and the context is filled anyway, + * it is used for implicit Windows-like inheritance + */ + +static BOOL ntfs_fuse_fill_security_context(fuse_req_t req, + struct SECURITY_CONTEXT *scx) +{ + const struct fuse_ctx *fusecontext; + + scx->vol = ctx->vol; + scx->mapping[MAPUSERS] = ctx->security.mapping[MAPUSERS]; + scx->mapping[MAPGROUPS] = ctx->security.mapping[MAPGROUPS]; + scx->pseccache = &ctx->seccache; + if (req) { + fusecontext = fuse_req_ctx(req); + scx->uid = fusecontext->uid; + scx->gid = fusecontext->gid; + scx->tid = fusecontext->pid; +#ifdef FUSE_CAP_DONT_MASK + /* the umask can be processed by the file system */ + scx->umask = fusecontext->umask; +#else + /* the umask if forced by fuse on creation */ + scx->umask = 0; +#endif + + } else { + scx->uid = 0; + scx->gid = 0; + scx->tid = 0; + scx->umask = 0; + } + return (ctx->security.mapping[MAPUSERS] != (struct MAPPING*)NULL); +} + +static u64 ntfs_fuse_inode_lookup(fuse_ino_t parent, const char *name) +{ + u64 ino = (u64)-1; + u64 inum; + ntfs_inode *dir_ni; + + /* Open target directory. */ + dir_ni = ntfs_inode_open(ctx->vol, INODE(parent)); + if (dir_ni) { + /* Lookup file */ + inum = ntfs_inode_lookup_by_mbsname(dir_ni, name); + if (ntfs_inode_close(dir_ni) + || (inum == (u64)-1)) + ino = (u64)-1; + else + ino = MREF(inum); + } + return (ino); +} + +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + +/* + * Check access to parent directory + * + * file inode is only opened when not fed in and S_ISVTX is requested, + * when already open and S_ISVTX, it *HAS TO* be fed in. + * + * returns 1 if allowed, + * 0 if not allowed or some error occurred (errno tells why) + */ + +static int ntfs_allowed_dir_access(struct SECURITY_CONTEXT *scx, + ntfs_inode *dir_ni, fuse_ino_t ino, + ntfs_inode *ni, mode_t accesstype) +{ + int allowed; + ntfs_inode *ni2; + struct stat stbuf; + + allowed = ntfs_allowed_access(scx, dir_ni, accesstype); + /* + * for an not-owned sticky directory, have to + * check whether file itself is owned + */ + if ((accesstype == (S_IWRITE + S_IEXEC + S_ISVTX)) + && (allowed == 2)) { + if (ni) + ni2 = ni; + else + ni2 = ntfs_inode_open(ctx->vol, INODE(ino)); + allowed = 0; + if (ni2) { + allowed = (ntfs_get_owner_mode(scx,ni2,&stbuf) >= 0) + && (stbuf.st_uid == scx->uid); + if (!ni) + ntfs_inode_close(ni2); + } + } + return (allowed); +} + +#endif /* !KERNELPERMS | (POSIXACLS & !KERNELACLS) */ + +/** + * ntfs_fuse_statfs - return information about mounted NTFS volume + * @path: ignored (but fuse requires it) + * @sfs: statfs structure in which to return the information + * + * Return information about the mounted NTFS volume @sb in the statfs structure + * pointed to by @sfs (this is initialized with zeros before ntfs_statfs is + * called). We interpret the values to be correct of the moment in time at + * which we are called. Most values are variable otherwise and this isn't just + * the free values but the totals as well. For example we can increase the + * total number of file nodes if we run out and we can keep doing this until + * there is no more space on the volume left at all. + * + * This code based on ntfs_statfs from ntfs kernel driver. + * + * Returns 0 on success or -errno on error. + */ + +static void ntfs_fuse_statfs(fuse_req_t req, + fuse_ino_t ino __attribute__((unused))) +{ + struct statvfs sfs; + s64 size; + int delta_bits; + ntfs_volume *vol; + + vol = ctx->vol; + if (vol) { + /* + * File system block size. Used to calculate used/free space by df. + * Incorrectly documented as "optimal transfer block size". + */ + sfs.f_bsize = vol->cluster_size; + + /* Fundamental file system block size, used as the unit. */ + sfs.f_frsize = vol->cluster_size; + + /* + * Total number of blocks on file system in units of f_frsize. + * Since inodes are also stored in blocks ($MFT is a file) hence + * this is the number of clusters on the volume. + */ + sfs.f_blocks = vol->nr_clusters; + + /* Free blocks available for all and for non-privileged processes. */ + size = vol->free_clusters; + if (size < 0) + size = 0; + sfs.f_bavail = sfs.f_bfree = size; + + /* Free inodes on the free space */ + delta_bits = vol->cluster_size_bits - vol->mft_record_size_bits; + if (delta_bits >= 0) + size <<= delta_bits; + else + size >>= -delta_bits; + + /* Number of inodes at this point in time. */ + sfs.f_files = (vol->mftbmp_na->allocated_size << 3) + size; + + /* Free inodes available for all and for non-privileged processes. */ + size += vol->free_mft_records; + if (size < 0) + size = 0; + sfs.f_ffree = sfs.f_favail = size; + + /* Maximum length of filenames. */ + sfs.f_namemax = NTFS_MAX_NAME_LEN; + fuse_reply_statfs(req, &sfs); + } else + fuse_reply_err(req, ENODEV); + +} + +static void set_fuse_error(int *err) +{ + if (!*err) + *err = -errno; +} + +#if 0 && (defined(__APPLE__) || defined(__DARWIN__)) /* Unfinished. */ +static int ntfs_macfuse_getxtimes(const char *org_path, + struct timespec *bkuptime, struct timespec *crtime) +{ + int res = 0; + ntfs_inode *ni; + char *path = NULL; + ntfschar *stream_name; + int stream_name_len; + + stream_name_len = ntfs_fuse_parse_path(org_path, &path, &stream_name); + if (stream_name_len < 0) + return stream_name_len; + memset(bkuptime, 0, sizeof(struct timespec)); + memset(crtime, 0, sizeof(struct timespec)); + ni = ntfs_pathname_to_inode(ctx->vol, NULL, path); + if (!ni) { + res = -errno; + goto exit; + } + + /* We have no backup timestamp in NTFS. */ + crtime->tv_sec = ni->creation_time; +exit: + if (ntfs_inode_close(ni)) + set_fuse_error(&res); + free(path); + if (stream_name_len) + free(stream_name); + return res; +} + +int ntfs_macfuse_setcrtime(const char *path, const struct timespec *tv) +{ + ntfs_inode *ni; + int res = 0; + + if (ntfs_fuse_is_named_data_stream(path)) + return -EINVAL; /* n/a for named data streams. */ + ni = ntfs_pathname_to_inode(ctx->vol, NULL, path); + if (!ni) + return -errno; + + if (tv) { + ni->creation_time = tv->tv_sec; + ntfs_fuse_update_times(ni, NTFS_UPDATE_CTIME); + } + + if (ntfs_inode_close(ni)) + set_fuse_error(&res); + return res; +} + +int ntfs_macfuse_setbkuptime(const char *path, const struct timespec *tv) +{ + ntfs_inode *ni; + int res = 0; + + if (ntfs_fuse_is_named_data_stream(path)) + return -EINVAL; /* n/a for named data streams. */ + ni = ntfs_pathname_to_inode(ctx->vol, NULL, path); + if (!ni) + return -errno; + + /* + * Only pretending to set backup time successfully to please the APIs of + * Mac OS X. In reality, NTFS has no backup time. + */ + + if (ntfs_inode_close(ni)) + set_fuse_error(&res); + return res; +} + +int ntfs_macfuse_setchgtime(const char *path, const struct timespec *tv) +{ + ntfs_inode *ni; + int res = 0; + + if (ntfs_fuse_is_named_data_stream(path)) + return -EINVAL; /* n/a for named data streams. */ + ni = ntfs_pathname_to_inode(ctx->vol, NULL, path); + if (!ni) + return -errno; + + if (tv) { + ni->last_mft_change_time = tv->tv_sec; + ntfs_fuse_update_times(ni, 0); + } + + if (ntfs_inode_close(ni)) + set_fuse_error(&res); + return res; +} +#endif /* defined(__APPLE__) || defined(__DARWIN__) */ + +#if defined(FUSE_CAP_DONT_MASK) || (defined(__APPLE__) || defined(__DARWIN__)) +static void ntfs_init(void *userdata __attribute__((unused)), + struct fuse_conn_info *conn) +{ +#if defined(__APPLE__) || defined(__DARWIN__) + FUSE_ENABLE_XTIMES(conn); +#endif +#ifdef FUSE_CAP_DONT_MASK + /* request umask not to be enforced by fuse */ + conn->want |= FUSE_CAP_DONT_MASK; +#endif /* defined FUSE_CAP_DONT_MASK */ +} +#endif /* defined(FUSE_CAP_DONT_MASK) || (defined(__APPLE__) || defined(__DARWIN__)) */ + +static int ntfs_fuse_getstat(struct SECURITY_CONTEXT *scx, + ntfs_inode *ni, struct stat *stbuf) +{ + int res = 0; + ntfs_attr *na; + BOOL withusermapping; + + memset(stbuf, 0, sizeof(struct stat)); + withusermapping = (scx->mapping[MAPUSERS] != (struct MAPPING*)NULL); + if ((ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) + || (ni->flags & FILE_ATTR_REPARSE_POINT)) { + if (ni->flags & FILE_ATTR_REPARSE_POINT) { + char *target; + int attr_size; + + errno = 0; + target = ntfs_make_symlink(ni, ctx->abs_mnt_point, + &attr_size); + /* + * If the reparse point is not a valid + * directory junction, and there is no error + * we still display as a symlink + */ + if (target || (errno == EOPNOTSUPP)) { + /* returning attribute size */ + if (target) + stbuf->st_size = attr_size; + else + stbuf->st_size = + sizeof(ntfs_bad_reparse); + stbuf->st_blocks = + (ni->allocated_size + 511) >> 9; + stbuf->st_nlink = + le16_to_cpu(ni->mrec->link_count); + stbuf->st_mode = S_IFLNK; + free(target); + } else { + res = -errno; + goto exit; + } + } else { + /* Directory. */ + stbuf->st_mode = S_IFDIR | (0777 & ~ctx->dmask); + /* get index size, if not known */ + if (!test_nino_flag(ni, KnownSize)) { + na = ntfs_attr_open(ni, AT_INDEX_ALLOCATION, + NTFS_INDEX_I30, 4); + if (na) { + ni->data_size = na->data_size; + ni->allocated_size = na->allocated_size; + set_nino_flag(ni, KnownSize); + ntfs_attr_close(na); + } + } + stbuf->st_size = ni->data_size; + stbuf->st_blocks = ni->allocated_size >> 9; + stbuf->st_nlink = 1; /* Make find(1) work */ + } + } else { + /* Regular or Interix (INTX) file. */ + stbuf->st_mode = S_IFREG; + stbuf->st_size = ni->data_size; +#ifdef HAVE_SETXATTR /* extended attributes interface required */ + /* + * return data size rounded to next 512 byte boundary for + * encrypted files to include padding required for decryption + * also include 2 bytes for padding info + */ + if (ctx->efs_raw && ni->flags & FILE_ATTR_ENCRYPTED) + stbuf->st_size = ((ni->data_size + 511) & ~511) + 2; +#endif /* HAVE_SETXATTR */ + /* + * Temporary fix to make ActiveSync work via Samba 3.0. + * See more on the ntfs-3g-devel list. + */ + stbuf->st_blocks = (ni->allocated_size + 511) >> 9; + stbuf->st_nlink = le16_to_cpu(ni->mrec->link_count); + if (ni->flags & FILE_ATTR_SYSTEM) { + na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0); + if (!na) { + goto exit; + } + /* Check whether it's Interix FIFO or socket. */ + if (!(ni->flags & FILE_ATTR_HIDDEN)) { + /* FIFO. */ + if (na->data_size == 0) + stbuf->st_mode = S_IFIFO; + /* Socket link. */ + if (na->data_size == 1) + stbuf->st_mode = S_IFSOCK; + } + /* + * Check whether it's Interix symbolic link, block or + * character device. + */ + if ((size_t)na->data_size <= sizeof(INTX_FILE_TYPES) + + sizeof(ntfschar) * PATH_MAX + && (size_t)na->data_size > + sizeof(INTX_FILE_TYPES)) { + INTX_FILE *intx_file; + + intx_file = + (INTX_FILE*)ntfs_malloc(na->data_size); + if (!intx_file) { + res = -errno; + ntfs_attr_close(na); + goto exit; + } + if (ntfs_attr_pread(na, 0, na->data_size, + intx_file) != na->data_size) { + res = -errno; + free(intx_file); + ntfs_attr_close(na); + goto exit; + } + if (intx_file->magic == INTX_BLOCK_DEVICE && + na->data_size == (s64)offsetof( + INTX_FILE, device_end)) { + stbuf->st_mode = S_IFBLK; + stbuf->st_rdev = makedev(le64_to_cpu( + intx_file->major), + le64_to_cpu( + intx_file->minor)); + } + if (intx_file->magic == INTX_CHARACTER_DEVICE && + na->data_size == (s64)offsetof( + INTX_FILE, device_end)) { + stbuf->st_mode = S_IFCHR; + stbuf->st_rdev = makedev(le64_to_cpu( + intx_file->major), + le64_to_cpu( + intx_file->minor)); + } + if (intx_file->magic == INTX_SYMBOLIC_LINK) + stbuf->st_mode = S_IFLNK; + free(intx_file); + } + ntfs_attr_close(na); + } + stbuf->st_mode |= (0777 & ~ctx->fmask); + } + if (withusermapping) { + if (ntfs_get_owner_mode(scx,ni,stbuf) < 0) + set_fuse_error(&res); + } else { + stbuf->st_uid = ctx->uid; + stbuf->st_gid = ctx->gid; + } + if (S_ISLNK(stbuf->st_mode)) + stbuf->st_mode |= 0777; + stbuf->st_ino = ni->mft_no; +#ifdef HAVE_STRUCT_STAT_ST_ATIMESPEC + stbuf->st_atimespec = ntfs2timespec(ni->last_access_time); + stbuf->st_ctimespec = ntfs2timespec(ni->last_mft_change_time); + stbuf->st_mtimespec = ntfs2timespec(ni->last_data_change_time); +#elif defined(HAVE_STRUCT_STAT_ST_ATIM) + stbuf->st_atim = ntfs2timespec(ni->last_access_time); + stbuf->st_ctim = ntfs2timespec(ni->last_mft_change_time); + stbuf->st_mtim = ntfs2timespec(ni->last_data_change_time); +#elif defined(HAVE_STRUCT_STAT_ST_ATIMENSEC) + { + struct timespec ts; + + ts = ntfs2timespec(ni->last_access_time); + stbuf->st_atime = ts.tv_sec; + stbuf->st_atimensec = ts.tv_nsec; + ts = ntfs2timespec(ni->last_mft_change_time); + stbuf->st_ctime = ts.tv_sec; + stbuf->st_ctimensec = ts.tv_nsec; + ts = ntfs2timespec(ni->last_data_change_time); + stbuf->st_mtime = ts.tv_sec; + stbuf->st_mtimensec = ts.tv_nsec; + } +#else +#warning "No known way to set nanoseconds in struct stat !" + { + struct timespec ts; + + ts = ntfs2timespec(ni->last_access_time); + stbuf->st_atime = ts.tv_sec; + ts = ntfs2timespec(ni->last_mft_change_time); + stbuf->st_ctime = ts.tv_sec; + ts = ntfs2timespec(ni->last_data_change_time); + stbuf->st_mtime = ts.tv_sec; + } +#endif +exit: + return (res); +} + +static void ntfs_fuse_getattr(fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *fi __attribute__((unused))) +{ + int res; + ntfs_inode *ni; + struct stat stbuf; + struct SECURITY_CONTEXT security; + + ni = ntfs_inode_open(ctx->vol, INODE(ino)); + if (!ni) + res = -errno; + else { + ntfs_fuse_fill_security_context(req, &security); + res = ntfs_fuse_getstat(&security, ni, &stbuf); + if (ntfs_inode_close(ni)) + set_fuse_error(&res); + } + if (!res) + fuse_reply_attr(req, &stbuf, ATTR_TIMEOUT); + else + fuse_reply_err(req, -res); +} + +static __inline__ BOOL ntfs_fuse_fillstat(struct SECURITY_CONTEXT *scx, + struct fuse_entry_param *pentry, u64 iref) +{ + ntfs_inode *ni; + BOOL ok = FALSE; + + pentry->ino = MREF(iref); + ni = ntfs_inode_open(ctx->vol, pentry->ino); + if (ni) { + if (!ntfs_fuse_getstat(scx, ni, &pentry->attr)) { + pentry->generation = 1; + pentry->attr_timeout = ATTR_TIMEOUT; + pentry->entry_timeout = ENTRY_TIMEOUT; + ok = TRUE; + } + if (ntfs_inode_close(ni)) + ok = FALSE; + } + return (ok); +} + + +static void ntfs_fuse_lookup(fuse_req_t req, fuse_ino_t parent, + const char *name) +{ + struct SECURITY_CONTEXT security; + struct fuse_entry_param entry; + ntfs_inode *dir_ni; + u64 iref; + BOOL ok = FALSE; + + if (strlen(name) < 256) { + dir_ni = ntfs_inode_open(ctx->vol, INODE(parent)); + if (dir_ni) { +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + /* + * make sure the parent directory is searchable + */ + if (ntfs_fuse_fill_security_context(req, &security) + && !ntfs_allowed_access(&security,dir_ni,S_IEXEC)) { + ntfs_inode_close(dir_ni); + errno = EACCES; + } else { +#else + ntfs_fuse_fill_security_context(req, &security); +#endif + iref = ntfs_inode_lookup_by_mbsname(dir_ni, + name); + ok = !ntfs_inode_close(dir_ni) + && (iref != (u64)-1) + && ntfs_fuse_fillstat( + &security,&entry,iref); +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + } +#endif + } + } else + errno = ENAMETOOLONG; + if (!ok) + fuse_reply_err(req, errno); + else + fuse_reply_entry(req, &entry); +} + +static void ntfs_fuse_readlink(fuse_req_t req, fuse_ino_t ino) +{ + ntfs_inode *ni = NULL; + ntfs_attr *na = NULL; + INTX_FILE *intx_file = NULL; + char *buf = (char*)NULL; + int res = 0; + + /* Get inode. */ + ni = ntfs_inode_open(ctx->vol, INODE(ino)); + if (!ni) { + res = -errno; + goto exit; + } + /* + * Reparse point : analyze as a junction point + */ + if (ni->flags & FILE_ATTR_REPARSE_POINT) { + int attr_size; + + errno = 0; + res = 0; + buf = ntfs_make_symlink(ni, ctx->abs_mnt_point, &attr_size); + if (!buf) { + if (errno == EOPNOTSUPP) + buf = strdup(ntfs_bad_reparse); + if (!buf) + res = -errno; + } + goto exit; + } + /* Sanity checks. */ + if (!(ni->flags & FILE_ATTR_SYSTEM)) { + res = -EINVAL; + goto exit; + } + na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0); + if (!na) { + res = -errno; + goto exit; + } + if ((size_t)na->data_size <= sizeof(INTX_FILE_TYPES)) { + res = -EINVAL; + goto exit; + } + if ((size_t)na->data_size > sizeof(INTX_FILE_TYPES) + + sizeof(ntfschar) * PATH_MAX) { + res = -ENAMETOOLONG; + goto exit; + } + /* Receive file content. */ + intx_file = (INTX_FILE*)ntfs_malloc(na->data_size); + if (!intx_file) { + res = -errno; + goto exit; + } + if (ntfs_attr_pread(na, 0, na->data_size, intx_file) != na->data_size) { + res = -errno; + goto exit; + } + /* Sanity check. */ + if (intx_file->magic != INTX_SYMBOLIC_LINK) { + res = -EINVAL; + goto exit; + } + /* Convert link from unicode to local encoding. */ + if (ntfs_ucstombs(intx_file->target, (na->data_size - + offsetof(INTX_FILE, target)) / sizeof(ntfschar), + &buf, 0) < 0) { + res = -errno; + goto exit; + } +exit: + if (intx_file) + free(intx_file); + if (na) + ntfs_attr_close(na); + if (ntfs_inode_close(ni)) + set_fuse_error(&res); + + if (res < 0) + fuse_reply_err(req, -res); + else + fuse_reply_readlink(req, buf); + if (buf != ntfs_bad_reparse) + free(buf); +} + +static int ntfs_fuse_filler(ntfs_fuse_fill_context_t *fill_ctx, + const ntfschar *name, const int name_len, const int name_type, + const s64 pos __attribute__((unused)), const MFT_REF mref, + const unsigned dt_type __attribute__((unused))) +{ + char *filename = NULL; + int ret = 0; + int filenamelen = -1; + size_t sz; + ntfs_fuse_fill_item_t *current; + ntfs_fuse_fill_item_t *newone; + + if (name_type == FILE_NAME_DOS) + return 0; + + if ((filenamelen = ntfs_ucstombs(name, name_len, &filename, 0)) < 0) { + ntfs_log_perror("Filename decoding failed (inode %llu)", + (unsigned long long)MREF(mref)); + return -1; + } + + if (MREF(mref) == FILE_root || MREF(mref) >= FILE_first_user || + ctx->show_sys_files) { + struct stat st = { .st_ino = MREF(mref) }; + + if (dt_type == NTFS_DT_REG) + st.st_mode = S_IFREG | (0777 & ~ctx->fmask); + else if (dt_type == NTFS_DT_DIR) + st.st_mode = S_IFDIR | (0777 & ~ctx->dmask); + +#if defined(__APPLE__) || defined(__DARWIN__) + /* + * Returning file names larger than MAXNAMLEN (255) bytes + * causes Darwin/Mac OS X to bug out and skip the entry. + */ + if (filenamelen > MAXNAMLEN) { + ntfs_log_debug("Truncating %d byte filename to " + "%d bytes.\n", filenamelen, MAXNAMLEN); + ntfs_log_debug(" before: '%s'\n", filename); + memset(filename + MAXNAMLEN, 0, filenamelen - MAXNAMLEN); + ntfs_log_debug(" after: '%s'\n", filename); + } +#endif /* defined(__APPLE__) || defined(__DARWIN__) */ + + current = fill_ctx->last; + sz = fuse_add_direntry(fill_ctx->req, + ¤t->buf[current->off], + current->bufsize - current->off, + filename, &st, current->off); + if (!sz || ((current->off + sz) > current->bufsize)) { + newone = (ntfs_fuse_fill_item_t*)ntfs_malloc + (sizeof(ntfs_fuse_fill_item_t) + + current->bufsize); + if (newone) { + newone->off = 0; + newone->bufsize = current->bufsize; + newone->next = (ntfs_fuse_fill_item_t*)NULL; + current->next = newone; + fill_ctx->last = newone; + current = newone; + sz = fuse_add_direntry(fill_ctx->req, + current->buf, + current->bufsize - current->off, + filename, &st, current->off); + if (!sz) { + errno = EIO; + ntfs_log_error("Could not add a" + " directory entry (inode %lld)\n", + (unsigned long long)MREF(mref)); + } + } else { + sz = 0; + errno = ENOMEM; + } + } + if (sz) { + current->off += sz; + } else { + ret = -1; + } + } + + free(filename); + return ret; +} + +static void ntfs_fuse_opendir(fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *fi) +{ + int res = 0; + ntfs_inode *ni; + int accesstype; + ntfs_fuse_fill_context_t *fill; + struct SECURITY_CONTEXT security; + + ni = ntfs_inode_open(ctx->vol, INODE(ino)); + if (ni) { + if (ntfs_fuse_fill_security_context(req, &security)) { + if (fi->flags & O_WRONLY) + accesstype = S_IWRITE; + else + if (fi->flags & O_RDWR) + accesstype = S_IWRITE | S_IREAD; + else + accesstype = S_IREAD; + if (!ntfs_allowed_access(&security,ni,accesstype)) + res = -EACCES; + } + if (ntfs_inode_close(ni)) + set_fuse_error(&res); + if (!res) { + fill = (ntfs_fuse_fill_context_t*) + ntfs_malloc(sizeof(ntfs_fuse_fill_context_t)); + if (!fill) + res = -errno; + else { + fill->first = fill->last + = (ntfs_fuse_fill_item_t*)NULL; + fill->filled = FALSE; + fill->ino = ino; + } + fi->fh = (long)fill; + } + } else + res = -errno; + if (!res) + fuse_reply_open(req, fi); + else + fuse_reply_err(req, -res); +} + + +static void ntfs_fuse_releasedir(fuse_req_t req, + fuse_ino_t ino __attribute__((unused)), + struct fuse_file_info *fi) +{ + ntfs_fuse_fill_context_t *fill; + ntfs_fuse_fill_item_t *current; + + fill = (ntfs_fuse_fill_context_t*)(long)fi->fh; + /* make sure to clear results */ + current = fill->first; + while (current) { + current = current->next; + free(fill->first); + fill->first = current; + } + free(fill); + fuse_reply_err(req, 0); +} + +static void ntfs_fuse_readdir(fuse_req_t req, fuse_ino_t ino, size_t size, + off_t off __attribute__((unused)), + struct fuse_file_info *fi __attribute__((unused))) +{ + ntfs_fuse_fill_item_t *first; + ntfs_fuse_fill_item_t *current; + ntfs_fuse_fill_context_t *fill; + ntfs_inode *ni; + s64 pos = 0; + int err = 0; + + fill = (ntfs_fuse_fill_context_t*)(long)fi->fh; + if (fill) { + if (!fill->filled) { + /* initial call : build the full list */ + first = (ntfs_fuse_fill_item_t*)ntfs_malloc + (sizeof(ntfs_fuse_fill_item_t) + size); + if (first) { + first->bufsize = size; + first->off = 0; + first->next = (ntfs_fuse_fill_item_t*)NULL; + fill->req = req; + fill->first = first; + fill->last = first; + ni = ntfs_inode_open(ctx->vol,INODE(ino)); + if (!ni) + err = -errno; + else { + if (ntfs_readdir(ni, &pos, fill, + (ntfs_filldir_t) + ntfs_fuse_filler)) + err = -errno; + fill->filled = TRUE; + ntfs_fuse_update_times(ni, + NTFS_UPDATE_ATIME); + if (ntfs_inode_close(ni)) + set_fuse_error(&err); + } + if (!err) + fuse_reply_buf(req, first->buf, + first->off); + /* reply sent, now must exit with no error */ + fill->first = first->next; + free(first); + } else + err = -errno; + } else { + /* subsequent call : return next non-empty buffer */ + current = fill->first; + while (current && !current->off) { + current = current->next; + free(fill->first); + fill->first = current; + } + if (current) { + fuse_reply_buf(req, current->buf, current->off); + fill->first = current->next; + free(current); + } else { + fuse_reply_buf(req, (char*)NULL, 0); + /* reply sent, now must exit with no error */ + } + } + } else { + errno = EIO; + err = -errno; + ntfs_log_error("Uninitialized fuse_readdir()\n"); + } + if (err) + fuse_reply_err(req, -err); +} + +static void ntfs_fuse_open(fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *fi) +{ + ntfs_inode *ni; + ntfs_attr *na; + struct open_file *of; + int state = 0; + char *path = NULL; + int res = 0; +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + int accesstype; + struct SECURITY_CONTEXT security; +#endif + + ni = ntfs_inode_open(ctx->vol, INODE(ino)); + if (ni) { + na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0); + if (na) { +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + if (ntfs_fuse_fill_security_context(req, &security)) { + if (fi->flags & O_WRONLY) + accesstype = S_IWRITE; + else + if (fi->flags & O_RDWR) + accesstype = S_IWRITE | S_IREAD; + else + accesstype = S_IREAD; + /* check whether requested access is allowed */ + if (!ntfs_allowed_access(&security, + ni,accesstype)) + res = -EACCES; + } +#endif + if ((res >= 0) + && (fi->flags & (O_WRONLY | O_RDWR))) { + /* mark a future need to compress the last chunk */ + if (na->data_flags & ATTR_COMPRESSION_MASK) + state |= CLOSE_COMPRESSED; +#ifdef HAVE_SETXATTR /* extended attributes interface required */ + /* mark a future need to fixup encrypted inode */ + if (ctx->efs_raw + && !(na->data_flags & ATTR_IS_ENCRYPTED) + && (ni->flags & FILE_ATTR_ENCRYPTED)) + state |= CLOSE_ENCRYPTED; +#endif /* HAVE_SETXATTR */ + } + ntfs_attr_close(na); + } else + res = -errno; + if (ntfs_inode_close(ni)) + set_fuse_error(&res); + } else + res = -errno; + free(path); + if (res >= 0) { + of = (struct open_file*)malloc(sizeof(struct open_file)); + if (of) { + of->parent = 0; + of->ino = ino; + of->state = state; + of->next = ctx->open_files; + of->previous = (struct open_file*)NULL; + if (ctx->open_files) + ctx->open_files->previous = of; + ctx->open_files = of; + fi->fh = (long)of; + } + } + if (res) + fuse_reply_err(req, -res); + else + fuse_reply_open(req, fi); +} + +static void ntfs_fuse_read(fuse_req_t req, fuse_ino_t ino, size_t size, + off_t offset, + struct fuse_file_info *fi __attribute__((unused))) +{ + ntfs_inode *ni = NULL; + ntfs_attr *na = NULL; + int res; + char *buf = (char*)NULL; + s64 total = 0; + s64 max_read; + + if (!size) + goto exit; + buf = (char*)ntfs_malloc(size); + if (!buf) { + res = -errno; + goto exit; + } + + ni = ntfs_inode_open(ctx->vol, INODE(ino)); + if (!ni) { + res = -errno; + goto exit; + } + na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0); + if (!na) { + res = -errno; + goto exit; + } + max_read = na->data_size; +#ifdef HAVE_SETXATTR /* extended attributes interface required */ + /* limit reads at next 512 byte boundary for encrypted attributes */ + if (ctx->efs_raw && (na->data_flags & ATTR_IS_ENCRYPTED) && + NAttrNonResident(na)) { + max_read = ((na->data_size+511) & ~511) + 2; + } +#endif /* HAVE_SETXATTR */ + if (offset + (off_t)size > max_read) { + if (max_read < offset) + goto ok; + size = max_read - offset; + } + while (size > 0) { + s64 ret = ntfs_attr_pread(na, offset, size, buf + total); + if (ret != (s64)size) + ntfs_log_perror("ntfs_attr_pread error reading inode %lld at " + "offset %lld: %lld <> %lld", (long long)ni->mft_no, + (long long)offset, (long long)size, (long long)ret); + if (ret <= 0 || ret > (s64)size) { + res = (ret < 0) ? -errno : -EIO; + goto exit; + } + size -= ret; + offset += ret; + total += ret; + } +ok: + ntfs_fuse_update_times(na->ni, NTFS_UPDATE_ATIME); + res = total; +exit: + if (na) + ntfs_attr_close(na); + if (ntfs_inode_close(ni)) + set_fuse_error(&res); + if (res < 0) + fuse_reply_err(req, -res); + else + fuse_reply_buf(req, buf, res); + free(buf); +} + +static void ntfs_fuse_write(fuse_req_t req, fuse_ino_t ino, const char *buf, + size_t size, off_t offset, + struct fuse_file_info *fi __attribute__((unused))) +{ + ntfs_inode *ni = NULL; + ntfs_attr *na = NULL; + int res, total = 0; + + ni = ntfs_inode_open(ctx->vol, INODE(ino)); + if (!ni) { + res = -errno; + goto exit; + } + na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0); + if (!na) { + res = -errno; + goto exit; + } + while (size) { + s64 ret = ntfs_attr_pwrite(na, offset, size, buf + total); + if (ret <= 0) { + res = -errno; + goto exit; + } + size -= ret; + offset += ret; + total += ret; + } + res = total; + if (res > 0) + ntfs_fuse_update_times(na->ni, NTFS_UPDATE_MCTIME); +exit: + if (na) + ntfs_attr_close(na); + if (total) + set_archive(ni); + if (ntfs_inode_close(ni)) + set_fuse_error(&res); + if (res < 0) + fuse_reply_err(req, -res); + else + fuse_reply_write(req, res); +} + +static int ntfs_fuse_chmod(struct SECURITY_CONTEXT *scx, fuse_ino_t ino, + mode_t mode, struct stat *stbuf) +{ + int res = 0; + ntfs_inode *ni; + + /* return unsupported if no user mapping has been defined */ + if (!scx->mapping[MAPUSERS] && !ctx->silent) { + res = -EOPNOTSUPP; + } else { + ni = ntfs_inode_open(ctx->vol, INODE(ino)); + if (!ni) + res = -errno; + else { + if (scx->mapping[MAPUSERS]) { + if (ntfs_set_mode(scx, ni, mode)) + res = -errno; + else { + ntfs_fuse_update_times(ni, + NTFS_UPDATE_CTIME); + /* + * Must return updated times, and + * inode has been updated, so hope + * we get no further errors + */ + res = ntfs_fuse_getstat(scx, ni, stbuf); + } + NInoSetDirty(ni); + } else + res = ntfs_fuse_getstat(scx, ni, stbuf); + if (ntfs_inode_close(ni)) + set_fuse_error(&res); + } + } + return res; +} + +static int ntfs_fuse_chown(struct SECURITY_CONTEXT *scx, fuse_ino_t ino, + uid_t uid, gid_t gid, struct stat *stbuf) +{ + ntfs_inode *ni; + int res; + + if (!scx->mapping[MAPUSERS] + && !ctx->silent + && ((uid != ctx->uid) || (gid != ctx->gid))) + res = -EOPNOTSUPP; + else { + res = 0; + ni = ntfs_inode_open(ctx->vol, INODE(ino)); + if (!ni) + res = -errno; + else { + if (scx->mapping[MAPUSERS] + && (((int)uid != -1) || ((int)gid != -1))) { + if (ntfs_set_owner(scx, ni, uid, gid)) + res = -errno; + else { + ntfs_fuse_update_times(ni, + NTFS_UPDATE_CTIME); + /* + * Must return updated times, and + * inode has been updated, so hope + * we get no further errors + */ + res = ntfs_fuse_getstat(scx, ni, stbuf); + } + } else + res = ntfs_fuse_getstat(scx, ni, stbuf); + if (ntfs_inode_close(ni)) + set_fuse_error(&res); + } + } + return (res); +} + +static int ntfs_fuse_chownmod(struct SECURITY_CONTEXT *scx, fuse_ino_t ino, + uid_t uid, gid_t gid, mode_t mode, struct stat *stbuf) +{ + ntfs_inode *ni; + int res; + + if (!scx->mapping[MAPUSERS] + && !ctx->silent + && ((uid != ctx->uid) || (gid != ctx->gid))) + res = -EOPNOTSUPP; + else { + res = 0; + ni = ntfs_inode_open(ctx->vol, INODE(ino)); + if (!ni) + res = -errno; + else { + if (scx->mapping[MAPUSERS]) { + if (ntfs_set_ownmod(scx, ni, uid, gid, mode)) + res = -errno; + else { + ntfs_fuse_update_times(ni, + NTFS_UPDATE_CTIME); + /* + * Must return updated times, and + * inode has been updated, so hope + * we get no further errors + */ + res = ntfs_fuse_getstat(scx, ni, stbuf); + } + } else + res = ntfs_fuse_getstat(scx, ni, stbuf); + if (ntfs_inode_close(ni)) + set_fuse_error(&res); + } + } + return (res); +} + +static int ntfs_fuse_trunc(struct SECURITY_CONTEXT *scx, fuse_ino_t ino, +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + off_t size, BOOL chkwrite, struct stat *stbuf) +#else + off_t size, BOOL chkwrite __attribute__((unused)), + struct stat *stbuf) +#endif +{ + ntfs_inode *ni = NULL; + ntfs_attr *na = NULL; + int res; + s64 oldsize; + + ni = ntfs_inode_open(ctx->vol, INODE(ino)); + if (!ni) + goto exit; + + na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0); + if (!na) + goto exit; +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + /* + * deny truncation if cannot write to file + * (already checked for ftruncate()) + */ + if (scx->mapping[MAPUSERS] + && chkwrite + && !ntfs_allowed_access(scx, ni, S_IWRITE)) { + errno = EACCES; + goto exit; + } +#endif + /* + * for compressed files, only deleting contents and expanding + * are implemented. Expanding is done by inserting a final + * zero, which is optimized as creating a hole when possible. + */ + if ((na->data_flags & ATTR_COMPRESSION_MASK) + && size + && (size < na->initialized_size)) { + errno = EOPNOTSUPP; + goto exit; + } + oldsize = na->data_size; + if ((na->data_flags & ATTR_COMPRESSION_MASK) + && (size > na->initialized_size)) { + char zero = 0; + if (ntfs_attr_pwrite(na, size - 1, 1, &zero) <= 0) + goto exit; + } else + if (ntfs_attr_truncate(na, size)) + goto exit; + if (oldsize != size) + set_archive(ni); + + ntfs_fuse_update_times(na->ni, NTFS_UPDATE_MCTIME); + res = ntfs_fuse_getstat(scx, ni, stbuf); + errno = (res ? -res : 0); +exit: + res = -errno; + ntfs_attr_close(na); + if (ntfs_inode_close(ni)) + set_fuse_error(&res); + return res; +} + +#ifdef HAVE_UTIMENSAT + +static int ntfs_fuse_utimens(struct SECURITY_CONTEXT *scx, fuse_ino_t ino, + struct stat *stin, struct stat *stbuf, int to_set) +{ + ntfs_inode *ni; + int res = 0; + + ni = ntfs_inode_open(ctx->vol, INODE(ino)); + if (!ni) + return -errno; + + /* no check or update if both UTIME_OMIT */ + if (to_set & (FUSE_SET_ATTR_ATIME + FUSE_SET_ATTR_MTIME)) { +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + if (ntfs_allowed_as_owner(scx, ni) + || ((to_set & FUSE_SET_ATTR_ATIME_NOW) + && (to_set & FUSE_SET_ATTR_MTIME_NOW) + && ntfs_allowed_access(scx, ni, S_IWRITE))) { +#endif + ntfs_time_update_flags mask = NTFS_UPDATE_CTIME; + + if (to_set & FUSE_SET_ATTR_ATIME_NOW) + mask |= NTFS_UPDATE_ATIME; + else + if (to_set & FUSE_SET_ATTR_ATIME) + ni->last_access_time + = timespec2ntfs(stin->st_atim); + if (to_set & FUSE_SET_ATTR_MTIME_NOW) + mask |= NTFS_UPDATE_MTIME; + else + if (to_set & FUSE_SET_ATTR_MTIME) + ni->last_data_change_time + = timespec2ntfs(stin->st_mtim); + ntfs_inode_update_times(ni, mask); +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + } else + res = -errno; +#endif + } + if (!res) + res = ntfs_fuse_getstat(scx, ni, stbuf); + if (ntfs_inode_close(ni)) + set_fuse_error(&res); + return res; +} + +#else /* HAVE_UTIMENSAT */ + +static int ntfs_fuse_utime(struct SECURITY_CONTEXT *scx, fuse_ino_t ino, + struct stat *stin, struct stat *stbuf) +{ + ntfs_inode *ni; + int res = 0; + struct timespec actime; + struct timespec modtime; +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + BOOL ownerok; + BOOL writeok; +#endif + + ni = ntfs_inode_open(ctx->vol, INODE(ino)); + if (!ni) + return -errno; + +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + ownerok = ntfs_allowed_as_owner(scx, ni); + if (stin) { + /* + * fuse never calls with a NULL buf and we do not + * know whether the specific condition can be applied + * So we have to accept updating by a non-owner having + * write access. + */ + writeok = !ownerok + && (stin->st_atime == stin->st_mtime) + && ntfs_allowed_access(scx, ni, S_IWRITE); + /* Must be owner */ + if (!ownerok && !writeok) + res = (stin->st_atime == stin->st_mtime + ? -EACCES : -EPERM); + else { + actime.tv_sec = stin->st_atime; + actime.tv_nsec = 0; + modtime.tv_sec = stin->st_mtime; + modtime.tv_nsec = 0; + ni->last_access_time = timespec2ntfs(actime); + ni->last_data_change_time = timespec2ntfs(modtime); + ntfs_fuse_update_times(ni, NTFS_UPDATE_CTIME); + } + } else { + /* Must be owner or have write access */ + writeok = !ownerok + && ntfs_allowed_access(scx, ni, S_IWRITE); + if (!ownerok && !writeok) + res = -EACCES; + else + ntfs_inode_update_times(ni, NTFS_UPDATE_AMCTIME); + } +#else + if (stin) { + actime.tv_sec = stin->st_atime; + actime.tv_nsec = 0; + modtime.tv_sec = stin->st_mtime; + modtime.tv_nsec = 0; + ni->last_access_time = timespec2ntfs(actime); + ni->last_data_change_time = timespec2ntfs(modtime); + ntfs_fuse_update_times(ni, NTFS_UPDATE_CTIME); + } else + ntfs_inode_update_times(ni, NTFS_UPDATE_AMCTIME); +#endif + + res = ntfs_fuse_getstat(scx, ni, stbuf); + if (ntfs_inode_close(ni)) + set_fuse_error(&res); + return res; +} + +#endif /* HAVE_UTIMENSAT */ + +static void ntfs_fuse_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr, + int to_set, struct fuse_file_info *fi __attribute__((unused))) +{ + struct stat stbuf; + ntfs_inode *ni; + int res; + struct SECURITY_CONTEXT security; + + res = 0; + ntfs_fuse_fill_security_context(req, &security); + /* no flags */ + if (!(to_set + & (FUSE_SET_ATTR_MODE + | FUSE_SET_ATTR_UID | FUSE_SET_ATTR_GID + | FUSE_SET_ATTR_SIZE + | FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME))) { + ni = ntfs_inode_open(ctx->vol, INODE(ino)); + if (!ni) + res = -errno; + else { + res = ntfs_fuse_getstat(&security, ni, &stbuf); + if (ntfs_inode_close(ni)) + set_fuse_error(&res); + } + } + /* some set of uid/gid/mode */ + if (to_set + & (FUSE_SET_ATTR_MODE + | FUSE_SET_ATTR_UID | FUSE_SET_ATTR_GID)) { + switch (to_set + & (FUSE_SET_ATTR_MODE + | FUSE_SET_ATTR_UID | FUSE_SET_ATTR_GID)) { + case FUSE_SET_ATTR_MODE : + res = ntfs_fuse_chmod(&security, ino, + attr->st_mode & 07777, &stbuf); + break; + case FUSE_SET_ATTR_UID : + res = ntfs_fuse_chown(&security, ino, attr->st_uid, + (gid_t)-1, &stbuf); + break; + case FUSE_SET_ATTR_GID : + res = ntfs_fuse_chown(&security, ino, (uid_t)-1, + attr->st_gid, &stbuf); + break; + case FUSE_SET_ATTR_UID + FUSE_SET_ATTR_GID : + res = ntfs_fuse_chown(&security, ino, attr->st_uid, + attr->st_gid, &stbuf); + break; + case FUSE_SET_ATTR_UID + FUSE_SET_ATTR_MODE: + res = ntfs_fuse_chownmod(&security, ino, attr->st_uid, + (gid_t)-1,attr->st_mode, + &stbuf); + break; + case FUSE_SET_ATTR_GID + FUSE_SET_ATTR_MODE: + res = ntfs_fuse_chownmod(&security, ino, (uid_t)-1, + attr->st_gid,attr->st_mode, + &stbuf); + break; + case FUSE_SET_ATTR_UID + FUSE_SET_ATTR_GID + FUSE_SET_ATTR_MODE: + res = ntfs_fuse_chownmod(&security, ino, attr->st_uid, + attr->st_gid,attr->st_mode, &stbuf); + break; + default : + break; + } + } + /* size */ + if (!res && (to_set & FUSE_SET_ATTR_SIZE)) { + res = ntfs_fuse_trunc(&security, ino, attr->st_size, + !fi, &stbuf); + } + /* some set of atime/mtime */ + if (!res && (to_set & (FUSE_SET_ATTR_ATIME + FUSE_SET_ATTR_MTIME))) { +#ifdef HAVE_UTIMENSAT + res = ntfs_fuse_utimens(&security, ino, attr, &stbuf, to_set); +#else /* HAVE_UTIMENSAT */ + res = ntfs_fuse_utime(&security, ino, attr, &stbuf); +#endif /* HAVE_UTIMENSAT */ + } + if (res) + fuse_reply_err(req, -res); + else + fuse_reply_attr(req, &stbuf, ATTR_TIMEOUT); +} + +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + +static void ntfs_fuse_access(fuse_req_t req, fuse_ino_t ino, int mask) +{ + int res = 0; + int mode; + ntfs_inode *ni; + struct SECURITY_CONTEXT security; + + /* JPA return unsupported if no user mapping has been defined */ + if (!ntfs_fuse_fill_security_context(req, &security)) { + if (ctx->silent) + res = 0; + else + res = -EOPNOTSUPP; + } else { + ni = ntfs_inode_open(ctx->vol, INODE(ino)); + if (!ni) { + res = -errno; + } else { + mode = 0; + if (mask & (X_OK | W_OK | R_OK)) { + if (mask & X_OK) mode += S_IEXEC; + if (mask & W_OK) mode += S_IWRITE; + if (mask & R_OK) mode += S_IREAD; + if (!ntfs_allowed_access(&security, + ni, mode)) + res = -errno; + } + if (ntfs_inode_close(ni)) + set_fuse_error(&res); + } + } + if (res < 0) + fuse_reply_err(req, -res); + else + fuse_reply_err(req, 0); +} + +#endif /* !KERNELPERMS | (POSIXACLS & !KERNELACLS) */ + +static int ntfs_fuse_create(fuse_req_t req, fuse_ino_t parent, const char *name, + mode_t typemode, dev_t dev, + struct fuse_entry_param *e, + const char *target, struct fuse_file_info *fi) +{ + ntfschar *uname = NULL, *utarget = NULL; + ntfs_inode *dir_ni = NULL, *ni; + struct open_file *of; + int state = 0; + le32 securid; + mode_t type = typemode & ~07777; + mode_t perm; + struct SECURITY_CONTEXT security; + int res = 0, uname_len, utarget_len; + + /* Generate unicode filename. */ + uname_len = ntfs_mbstoucs(name, &uname); + if (uname_len < 0) { + res = -errno; + goto exit; + } + /* Open parent directory. */ + dir_ni = ntfs_inode_open(ctx->vol, INODE(parent)); + if (!dir_ni) { + res = -errno; + goto exit; + } +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + /* make sure parent directory is writeable and executable */ + if (!ntfs_fuse_fill_security_context(req, &security) + || ntfs_allowed_access(&security, + dir_ni,S_IWRITE + S_IEXEC)) { +#else + ntfs_fuse_fill_security_context(req, &security); +#endif + if (S_ISDIR(type)) + perm = typemode & ~ctx->dmask & 0777; + else + perm = typemode & ~ctx->fmask & 0777; + /* + * Try to get a security id available for + * file creation (from inheritance or argument). + * This is not possible for NTFS 1.x, and we will + * have to build a security attribute later. + */ + if (!ctx->security.mapping[MAPUSERS]) + securid = const_cpu_to_le32(0); + else + if (ctx->inherit) + securid = ntfs_inherited_id(&security, + dir_ni, S_ISDIR(type)); + else +#if POSIXACLS + securid = ntfs_alloc_securid(&security, + security.uid, security.gid, + dir_ni, perm, S_ISDIR(type)); +#else + securid = ntfs_alloc_securid(&security, + security.uid, security.gid, + perm & ~security.umask, S_ISDIR(type)); +#endif + /* Create object specified in @type. */ + switch (type) { + case S_IFCHR: + case S_IFBLK: + ni = ntfs_create_device(dir_ni, securid, + uname, uname_len, type, dev); + break; + case S_IFLNK: + utarget_len = ntfs_mbstoucs(target, &utarget); + if (utarget_len < 0) { + res = -errno; + goto exit; + } + ni = ntfs_create_symlink(dir_ni, securid, + uname, uname_len, + utarget, utarget_len); + break; + default: + ni = ntfs_create(dir_ni, securid, uname, + uname_len, type); + break; + } + if (ni) { + /* + * set the security attribute if a security id + * could not be allocated (eg NTFS 1.x) + */ + if (ctx->security.mapping[MAPUSERS]) { +#if POSIXACLS + if (!securid + && ntfs_set_inherited_posix(&security, ni, + security.uid, security.gid, + dir_ni, perm) < 0) + set_fuse_error(&res); +#else + if (!securid + && ntfs_set_owner_mode(&security, ni, + security.uid, security.gid, + perm & ~security.umask) < 0) + set_fuse_error(&res); +#endif + } + set_archive(ni); + /* mark a need to compress the end of file */ + if (fi && (ni->flags & FILE_ATTR_COMPRESSED)) { + state |= CLOSE_COMPRESSED; + } +#ifdef HAVE_SETXATTR /* extended attributes interface required */ + /* mark a future need to fixup encrypted inode */ + if (fi + && ctx->efs_raw + && (ni->flags & FILE_ATTR_ENCRYPTED)) + state |= CLOSE_ENCRYPTED; +#endif /* HAVE_SETXATTR */ + ntfs_inode_update_mbsname(dir_ni, name, ni->mft_no); + NInoSetDirty(ni); + e->ino = ni->mft_no; + e->generation = 1; + e->attr_timeout = ATTR_TIMEOUT; + e->entry_timeout = ENTRY_TIMEOUT; + res = ntfs_fuse_getstat(&security, ni, &e->attr); + /* + * closing ni requires access to dir_ni to + * synchronize the index, avoid double opening. + */ + if (ntfs_inode_close_in_dir(ni, dir_ni)) + set_fuse_error(&res); + ntfs_fuse_update_times(dir_ni, NTFS_UPDATE_MCTIME); + } else + res = -errno; +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + } else + res = -errno; +#endif + +exit: + free(uname); + if (ntfs_inode_close(dir_ni)) + set_fuse_error(&res); + if (utarget) + free(utarget); + if ((res >= 0) && fi) { + of = (struct open_file*)malloc(sizeof(struct open_file)); + if (of) { + of->parent = 0; + of->ino = e->ino; + of->state = state; + of->next = ctx->open_files; + of->previous = (struct open_file*)NULL; + if (ctx->open_files) + ctx->open_files->previous = of; + ctx->open_files = of; + fi->fh = (long)of; + } + } + return res; +} + +static void ntfs_fuse_create_file(fuse_req_t req, fuse_ino_t parent, + const char *name, mode_t mode, + struct fuse_file_info *fi) +{ + int res; + struct fuse_entry_param entry; + + res = ntfs_fuse_create(req, parent, name, mode & (S_IFMT | 07777), + 0, &entry, NULL, fi); + if (res < 0) + fuse_reply_err(req, -res); + else + fuse_reply_create(req, &entry, fi); +} + +static void ntfs_fuse_mknod(fuse_req_t req, fuse_ino_t parent, const char *name, + mode_t mode, dev_t rdev) +{ + int res; + struct fuse_entry_param e; + + res = ntfs_fuse_create(req, parent, name, mode & (S_IFMT | 07777), + rdev, &e,NULL,(struct fuse_file_info*)NULL); + if (res < 0) + fuse_reply_err(req, -res); + else + fuse_reply_entry(req, &e); +} + +static void ntfs_fuse_symlink(fuse_req_t req, const char *target, + fuse_ino_t parent, const char *name) +{ + int res; + struct fuse_entry_param entry; + + res = ntfs_fuse_create(req, parent, name, S_IFLNK, 0, + &entry, target, (struct fuse_file_info*)NULL); + if (res < 0) + fuse_reply_err(req, -res); + else + fuse_reply_entry(req, &entry); +} + + +static int ntfs_fuse_newlink(fuse_req_t req __attribute__((unused)), + fuse_ino_t ino, fuse_ino_t newparent, + const char *newname, struct fuse_entry_param *e) +{ + ntfschar *uname = NULL; + ntfs_inode *dir_ni = NULL, *ni; + int res = 0, uname_len; + struct SECURITY_CONTEXT security; + + /* Open file for which create hard link. */ + ni = ntfs_inode_open(ctx->vol, INODE(ino)); + if (!ni) { + res = -errno; + goto exit; + } + + /* Generate unicode filename. */ + uname_len = ntfs_mbstoucs(newname, &uname); + if (uname_len < 0) { + res = -errno; + goto exit; + } + /* Open parent directory. */ + dir_ni = ntfs_inode_open(ctx->vol, INODE(newparent)); + if (!dir_ni) { + res = -errno; + goto exit; + } + +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + /* make sure the target parent directory is writeable */ + if (ntfs_fuse_fill_security_context(req, &security) + && !ntfs_allowed_access(&security,dir_ni,S_IWRITE + S_IEXEC)) + res = -EACCES; + else +#else + ntfs_fuse_fill_security_context(req, &security); +#endif + { + if (ntfs_link(ni, dir_ni, uname, uname_len)) { + res = -errno; + goto exit; + } + ntfs_inode_update_mbsname(dir_ni, newname, ni->mft_no); + if (e) { + e->ino = ni->mft_no; + e->generation = 1; + e->attr_timeout = ATTR_TIMEOUT; + e->entry_timeout = ENTRY_TIMEOUT; + res = ntfs_fuse_getstat(&security, ni, &e->attr); + } + set_archive(ni); + ntfs_fuse_update_times(ni, NTFS_UPDATE_CTIME); + ntfs_fuse_update_times(dir_ni, NTFS_UPDATE_MCTIME); + } +exit: + /* + * Must close dir_ni first otherwise ntfs_inode_sync_file_name(ni) + * may fail because ni may not be in parent's index on the disk yet. + */ + if (ntfs_inode_close(dir_ni)) + set_fuse_error(&res); + if (ntfs_inode_close(ni)) + set_fuse_error(&res); + free(uname); + return (res); +} + +static void ntfs_fuse_link(fuse_req_t req, fuse_ino_t ino, + fuse_ino_t newparent, const char *newname) +{ + struct fuse_entry_param entry; + int res; + + res = ntfs_fuse_newlink(req, ino, newparent, newname, &entry); + if (res) + fuse_reply_err(req, -res); + else + fuse_reply_entry(req, &entry); +} + +static int ntfs_fuse_rm(fuse_req_t req, fuse_ino_t parent, const char *name) +{ + ntfschar *uname = NULL; + ntfs_inode *dir_ni = NULL, *ni = NULL; + int res = 0, uname_len; + u64 iref; + fuse_ino_t ino; + struct open_file *of; + char ghostname[GHOSTLTH]; +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + struct SECURITY_CONTEXT security; +#endif + + /* Open parent directory. */ + dir_ni = ntfs_inode_open(ctx->vol, INODE(parent)); + if (!dir_ni) { + res = -errno; + goto exit; + } + /* Generate unicode filename. */ + uname_len = ntfs_mbstoucs(name, &uname); + if (uname_len < 0) { + res = -errno; + goto exit; + } + /* Open object for delete. */ + iref = ntfs_inode_lookup_by_mbsname(dir_ni, name); + if (iref == (u64)-1) { + res = -errno; + goto exit; + } + +{ /* temporary */ +struct open_file *prev = (struct open_file*)NULL; +for (of=ctx->open_files; of; of=of->next) +{ +if (of->previous != prev) ntfs_log_error("bad chaining\n"); +prev = of; +} +} + of = ctx->open_files; + ino = (fuse_ino_t)MREF(iref); + /* improvable search in open files list... */ + while (of + && (of->ino != ino)) + of = of->next; + if (of && !(of->state & CLOSE_GHOST)) { + /* file was open, create a ghost in unlink parent */ + of->state |= CLOSE_GHOST; + of->parent = parent; + of->ghost = ++ctx->latest_ghost; + sprintf(ghostname,ghostformat,of->ghost); + /* need to close the dir for linking the ghost */ + if (ntfs_inode_close(dir_ni)) { + res = -errno; + goto out; + } + /* sweep existing ghost if any */ + ntfs_fuse_rm(req, parent, ghostname); + res = ntfs_fuse_newlink(req, of->ino, parent, ghostname, + (struct fuse_entry_param*)NULL); + if (res) + goto out; + /* now reopen then parent directory */ + dir_ni = ntfs_inode_open(ctx->vol, INODE(parent)); + if (!dir_ni) { + res = -errno; + goto exit; + } + } + + ni = ntfs_inode_open(ctx->vol, MREF(iref)); + if (!ni) { + res = -errno; + goto exit; + } + +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + /* JPA deny unlinking if directory is not writable and executable */ + if (!ntfs_fuse_fill_security_context(req, &security) + || ntfs_allowed_dir_access(&security, dir_ni, ino, ni, + S_IEXEC + S_IWRITE + S_ISVTX)) { +#endif + if (ntfs_delete(ctx->vol, (char*)NULL, ni, dir_ni, + uname, uname_len)) + res = -errno; + /* ntfs_delete() always closes ni and dir_ni */ + ni = dir_ni = NULL; +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + } else + res = -EACCES; +#endif +exit: + if (ntfs_inode_close(ni)) + set_fuse_error(&res); + if (ntfs_inode_close(dir_ni)) + set_fuse_error(&res); +out : + free(uname); + return res; +} + +static void ntfs_fuse_unlink(fuse_req_t req, fuse_ino_t parent, + const char *name) +{ + int res; + + res = ntfs_fuse_rm(req, parent, name); + if (res) + fuse_reply_err(req, -res); + else + fuse_reply_err(req, 0); +} + +static int ntfs_fuse_safe_rename(fuse_req_t req, fuse_ino_t ino, + fuse_ino_t parent, const char *name, fuse_ino_t xino, + fuse_ino_t newparent, const char *newname, + const char *tmp) +{ + int ret; + + ntfs_log_trace("Entering\n"); + + ret = ntfs_fuse_newlink(req, xino, newparent, tmp, + (struct fuse_entry_param*)NULL); + if (ret) + return ret; + + ret = ntfs_fuse_rm(req, newparent, newname); + if (!ret) { + + ret = ntfs_fuse_newlink(req, ino, newparent, newname, + (struct fuse_entry_param*)NULL); + if (ret) + goto restore; + + ret = ntfs_fuse_rm(req, parent, name); + if (ret) { + if (ntfs_fuse_rm(req, newparent, newname)) + goto err; + goto restore; + } + } + + goto cleanup; +restore: + if (ntfs_fuse_newlink(req, xino, newparent, newname, + (struct fuse_entry_param*)NULL)) { +err: + ntfs_log_perror("Rename failed. Existing file '%s' was renamed " + "to '%s'", newname, tmp); + } else { +cleanup: + /* + * Condition for this unlink has already been checked in + * "ntfs_fuse_rename_existing_dest()", so it should never + * fail (unless concurrent access to directories when fuse + * is multithreaded) + */ + if (ntfs_fuse_rm(req, newparent, tmp) < 0) + ntfs_log_perror("Rename failed. Existing file '%s' still present " + "as '%s'", newname, tmp); + } + return ret; +} + +static int ntfs_fuse_rename_existing_dest(fuse_req_t req, fuse_ino_t ino, + fuse_ino_t parent, const char *name, + fuse_ino_t xino, fuse_ino_t newparent, + const char *newname) +{ + int ret, len; + char *tmp; + const char *ext = ".ntfs-3g-"; +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + ntfs_inode *newdir_ni; + struct SECURITY_CONTEXT security; +#endif + + ntfs_log_trace("Entering\n"); + + len = strlen(newname) + strlen(ext) + 10 + 1; /* wc(str(2^32)) + \0 */ + tmp = (char*)ntfs_malloc(len); + if (!tmp) + return -errno; + + ret = snprintf(tmp, len, "%s%s%010d", newname, ext, ++ntfs_sequence); + if (ret != len - 1) { + ntfs_log_error("snprintf failed: %d != %d\n", ret, len - 1); + ret = -EOVERFLOW; + } else { +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + /* + * Make sure existing dest can be removed. + * This is only needed if parent directory is + * sticky, because in this situation condition + * for unlinking is different from condition for + * linking + */ + newdir_ni = ntfs_inode_open(ctx->vol, INODE(newparent)); + if (newdir_ni) { + if (!ntfs_fuse_fill_security_context(req,&security) + || ntfs_allowed_dir_access(&security, newdir_ni, + xino, (ntfs_inode*)NULL, + S_IEXEC + S_IWRITE + S_ISVTX)) { + if (ntfs_inode_close(newdir_ni)) + ret = -errno; + else + ret = ntfs_fuse_safe_rename(req, ino, + parent, name, xino, + newparent, newname, + tmp); + } else { + ntfs_inode_close(newdir_ni); + ret = -EACCES; + } + } else + ret = -errno; +#else + ret = ntfs_fuse_safe_rename(req, ino, parent, name, + xino, newparent, newname, tmp); +#endif + } + free(tmp); + return ret; +} + +static void ntfs_fuse_rename(fuse_req_t req, fuse_ino_t parent, + const char *name, fuse_ino_t newparent, + const char *newname) +{ + int ret; + fuse_ino_t ino; + fuse_ino_t xino; + ntfs_inode *ni; + + ntfs_log_debug("rename: old: '%s' new: '%s'\n", name, newname); + + /* + * FIXME: Rename should be atomic. + */ + + ino = ntfs_fuse_inode_lookup(parent, name); + if (ino == (fuse_ino_t)-1) { + ret = -errno; + goto out; + } + /* Check whether target is present */ + xino = ntfs_fuse_inode_lookup(newparent, newname); + if (xino != (fuse_ino_t)-1) { + /* + * Target exists : no need to check whether it + * designates the same inode, this has already + * been checked (by fuse ?) + */ + ni = ntfs_inode_open(ctx->vol, INODE(xino)); + if (!ni) + ret = -errno; + else { + ret = ntfs_check_empty_dir(ni); + if (ret < 0) { + ret = -errno; + ntfs_inode_close(ni); + goto out; + } + + if (ntfs_inode_close(ni)) { + set_fuse_error(&ret); + goto out; + } + ret = ntfs_fuse_rename_existing_dest(req, ino, parent, + name, xino, newparent, newname); + } + } else { + /* target does not exist */ + ret = ntfs_fuse_newlink(req, ino, newparent, newname, + (struct fuse_entry_param*)NULL); + if (ret) + goto out; + + ret = ntfs_fuse_rm(req, parent, name); + if (ret) + ntfs_fuse_rm(req, newparent, newname); + } +out: + if (ret) + fuse_reply_err(req, -ret); + else + fuse_reply_err(req, 0); +} + +static void ntfs_fuse_release(fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *fi) +{ + ntfs_inode *ni = NULL; + ntfs_attr *na = NULL; + struct open_file *of; + char ghostname[GHOSTLTH]; + int res; + + of = (struct open_file*)(long)fi->fh; + /* Only for marked descriptors there is something to do */ + if (!of || !(of->state & (CLOSE_COMPRESSED | CLOSE_ENCRYPTED))) { + res = 0; + goto out; + } + ni = ntfs_inode_open(ctx->vol, INODE(ino)); + if (!ni) { + res = -errno; + goto exit; + } + na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0); + if (!na) { + res = -errno; + goto exit; + } + res = 0; + if (of->state & CLOSE_COMPRESSED) + res = ntfs_attr_pclose(na); +#ifdef HAVE_SETXATTR /* extended attributes interface required */ + if (of->state & CLOSE_ENCRYPTED) + res = ntfs_efs_fixup_attribute(NULL, na); +#endif /* HAVE_SETXATTR */ +exit: + if (na) + ntfs_attr_close(na); + if (ntfs_inode_close(ni)) + set_fuse_error(&res); +out: + /* remove the associate ghost file (even if release failed) */ + if (of) { + if (of->state & CLOSE_GHOST) { + sprintf(ghostname,ghostformat,of->ghost); + ntfs_fuse_rm(req, of->parent, ghostname); + } + /* remove from open files list */ + if (of->next) + of->next->previous = of->previous; + if (of->previous) + of->previous->next = of->next; + else + ctx->open_files = of->next; + free(of); + } + if (res) + fuse_reply_err(req, -res); + else + fuse_reply_err(req, 0); +} + +static void ntfs_fuse_mkdir(fuse_req_t req, fuse_ino_t parent, + const char *name, mode_t mode) +{ + int res; + struct fuse_entry_param entry; + + res = ntfs_fuse_create(req, parent, name, S_IFDIR | (mode & 07777), + 0, &entry, (char*)NULL, (struct fuse_file_info*)NULL); + if (res < 0) + fuse_reply_err(req, -res); + else + fuse_reply_entry(req, &entry); +} + +static void ntfs_fuse_rmdir(fuse_req_t req, fuse_ino_t parent, const char *name) +{ + int res; + + res = ntfs_fuse_rm(req, parent, name); + if (res) + fuse_reply_err(req, -res); + else + fuse_reply_err(req, 0); +} + +static void ntfs_fuse_bmap(fuse_req_t req, fuse_ino_t ino, size_t blocksize, + uint64_t vidx) +{ + ntfs_inode *ni; + ntfs_attr *na; + LCN lcn; + uint64_t lidx = 0; + int ret = 0; + int cl_per_bl = ctx->vol->cluster_size / blocksize; + + if (blocksize > ctx->vol->cluster_size) { + ret = -EINVAL; + goto done; + } + + ni = ntfs_inode_open(ctx->vol, INODE(ino)); + if (!ni) { + ret = -errno; + goto done; + } + + na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0); + if (!na) { + ret = -errno; + goto close_inode; + } + + if ((na->data_flags & (ATTR_COMPRESSION_MASK | ATTR_IS_ENCRYPTED)) + || !NAttrNonResident(na)) { + ret = -EINVAL; + goto close_attr; + } + + if (ntfs_attr_map_whole_runlist(na)) { + ret = -errno; + goto close_attr; + } + + lcn = ntfs_rl_vcn_to_lcn(na->rl, vidx / cl_per_bl); + lidx = (lcn > 0) ? lcn * cl_per_bl + vidx % cl_per_bl : 0; + +close_attr: + ntfs_attr_close(na); +close_inode: + if (ntfs_inode_close(ni)) + set_fuse_error(&ret); +done : + if (ret < 0) + fuse_reply_err(req, -ret); + else + fuse_reply_bmap(req, lidx); +} + +#ifdef HAVE_SETXATTR + +/* + * Name space identifications and prefixes + */ + +enum { XATTRNS_NONE, + XATTRNS_USER, + XATTRNS_SYSTEM, + XATTRNS_SECURITY, + XATTRNS_TRUSTED, + XATTRNS_OPEN } ; + +static const char nf_ns_user_prefix[] = "user."; +static const int nf_ns_user_prefix_len = sizeof(nf_ns_user_prefix) - 1; +static const char nf_ns_system_prefix[] = "system."; +static const int nf_ns_system_prefix_len = sizeof(nf_ns_system_prefix) - 1; +static const char nf_ns_security_prefix[] = "security."; +static const int nf_ns_security_prefix_len = sizeof(nf_ns_security_prefix) - 1; +static const char nf_ns_trusted_prefix[] = "trusted."; +static const int nf_ns_trusted_prefix_len = sizeof(nf_ns_trusted_prefix) - 1; + +static const char xattr_ntfs_3g[] = "ntfs-3g."; + +/* + * Identification of data mapped to the system name space + */ + +enum { XATTR_UNMAPPED, + XATTR_NTFS_ACL, + XATTR_NTFS_ATTRIB, + XATTR_NTFS_EFSINFO, + XATTR_NTFS_REPARSE_DATA, + XATTR_NTFS_OBJECT_ID, + XATTR_NTFS_DOS_NAME, + XATTR_NTFS_TIMES, + XATTR_POSIX_ACC, + XATTR_POSIX_DEF } ; + +static const char nf_ns_xattr_ntfs_acl[] = "system.ntfs_acl"; +static const char nf_ns_xattr_attrib[] = "system.ntfs_attrib"; +static const char nf_ns_xattr_efsinfo[] = "user.ntfs.efsinfo"; +static const char nf_ns_xattr_reparse[] = "system.ntfs_reparse_data"; +static const char nf_ns_xattr_object_id[] = "system.ntfs_object_id"; +static const char nf_ns_xattr_dos_name[] = "system.ntfs_dos_name"; +static const char nf_ns_xattr_times[] = "system.ntfs_times"; +static const char nf_ns_xattr_posix_access[] = "system.posix_acl_access"; +static const char nf_ns_xattr_posix_default[] = "system.posix_acl_default"; + +struct XATTRNAME { + int xattr; + const char *name; +} ; + +static struct XATTRNAME nf_ns_xattr_names[] = { + { XATTR_NTFS_ACL, nf_ns_xattr_ntfs_acl }, + { XATTR_NTFS_ATTRIB, nf_ns_xattr_attrib }, + { XATTR_NTFS_EFSINFO, nf_ns_xattr_efsinfo }, + { XATTR_NTFS_REPARSE_DATA, nf_ns_xattr_reparse }, + { XATTR_NTFS_OBJECT_ID, nf_ns_xattr_object_id }, + { XATTR_NTFS_DOS_NAME, nf_ns_xattr_dos_name }, + { XATTR_NTFS_TIMES, nf_ns_xattr_times }, + { XATTR_POSIX_ACC, nf_ns_xattr_posix_access }, + { XATTR_POSIX_DEF, nf_ns_xattr_posix_default }, + { XATTR_UNMAPPED, (char*)NULL } /* terminator */ +}; + +/* + * Check whether access to internal data as an extended + * attribute in system name space is allowed + * + * Returns pointer to inode if allowed, + * NULL and errno set if not allowed + */ + +static ntfs_inode *ntfs_check_access_xattr(fuse_req_t req, + struct SECURITY_CONTEXT *security, + fuse_ino_t ino, int attr, BOOL setting) +{ + ntfs_inode *dir_ni; + ntfs_inode *ni; + BOOL foracl; + BOOL bad; + mode_t acctype; + + ni = (ntfs_inode*)NULL; + foracl = (attr == XATTR_POSIX_ACC) + || (attr == XATTR_POSIX_DEF); + /* + * When accessing Posix ACL, return unsupported if ACL + * were disabled or no user mapping has been defined. + * However no error will be returned to getfacl + */ + if ((!ntfs_fuse_fill_security_context(req, security) + || (ctx->secure_flags + & ((1 << SECURITY_DEFAULT) | (1 << SECURITY_RAW)))) + && foracl) { + errno = EOPNOTSUPP; + } else { + /* + * parent directory must be executable, and + * for setting a DOS name it must be writeable + */ + if (setting && (attr == XATTR_NTFS_DOS_NAME)) + acctype = S_IEXEC | S_IWRITE; + else + acctype = S_IEXEC; + ni = ntfs_inode_open(ctx->vol, INODE(ino)); + /* basic access was checked previously in a lookup */ + if (ni && (acctype != S_IEXEC)) { + bad = FALSE; + /* do not reopen root */ + if (ni->mft_no == FILE_root) { + /* forbid getting/setting names on root */ + if ((attr == XATTR_NTFS_DOS_NAME) + || !ntfs_real_allowed_access(security, + ni, acctype)) + bad = TRUE; + } else { + dir_ni = ntfs_dir_parent_inode(ni); + if (dir_ni) { + if (!ntfs_real_allowed_access(security, + dir_ni, acctype)) + bad = TRUE; + if (ntfs_inode_close(dir_ni)) + bad = TRUE; + } else + bad = TRUE; + } + if (bad) { + ntfs_inode_close(ni); + ni = (ntfs_inode*)NULL; + } + } + } + return (ni); +} + +/* + * Determine whether an extended attribute is in the system + * name space and mapped to internal data + */ + +static int mapped_xattr_system(const char *name) +{ + struct XATTRNAME *p; + + p = nf_ns_xattr_names; + while (p->name && strcmp(p->name,name)) + p++; + return (p->xattr); +} + +/* + * Determine the name space of an extended attribute + */ + +static int xattr_namespace(const char *name) +{ + int namespace; + + if (ctx->streams == NF_STREAMS_INTERFACE_XATTR) { + namespace = XATTRNS_NONE; + if (!strncmp(name, nf_ns_user_prefix, + nf_ns_user_prefix_len) + && (strlen(name) != (size_t)nf_ns_user_prefix_len)) + namespace = XATTRNS_USER; + else if (!strncmp(name, nf_ns_system_prefix, + nf_ns_system_prefix_len) + && (strlen(name) != (size_t)nf_ns_system_prefix_len)) + namespace = XATTRNS_SYSTEM; + else if (!strncmp(name, nf_ns_security_prefix, + nf_ns_security_prefix_len) + && (strlen(name) != (size_t)nf_ns_security_prefix_len)) + namespace = XATTRNS_SECURITY; + else if (!strncmp(name, nf_ns_trusted_prefix, + nf_ns_trusted_prefix_len) + && (strlen(name) != (size_t)nf_ns_trusted_prefix_len)) + namespace = XATTRNS_TRUSTED; + } else + namespace = XATTRNS_OPEN; + return (namespace); +} + +/* + * Fix the prefix of an extended attribute + */ + +static int fix_xattr_prefix(const char *name, int namespace, ntfschar **lename) +{ + int len; + char *prefixed; + + *lename = (ntfschar*)NULL; + switch (namespace) { + case XATTRNS_USER : + /* + * user name space : remove user prefix + */ + len = ntfs_mbstoucs(name + nf_ns_user_prefix_len, lename); + break; + case XATTRNS_SYSTEM : + case XATTRNS_SECURITY : + case XATTRNS_TRUSTED : + /* + * security, trusted and unmapped system name spaces : + * insert ntfs-3g prefix + */ + prefixed = (char*)ntfs_malloc(strlen(xattr_ntfs_3g) + + strlen(name) + 1); + if (prefixed) { + strcpy(prefixed,xattr_ntfs_3g); + strcat(prefixed,name); + len = ntfs_mbstoucs(prefixed, lename); + free(prefixed); + } else + len = -1; + break; + case XATTRNS_OPEN : + /* + * in open name space mode : do no fix prefix + */ + len = ntfs_mbstoucs(name, lename); + break; + default : + len = -1; + } + return (len); +} + +static void ntfs_fuse_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size) +{ + ntfs_attr_search_ctx *actx = NULL; + ntfs_inode *ni; + char *to; + char *list = (char*)NULL; + int ret = 0; +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + struct SECURITY_CONTEXT security; +#endif + +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + ntfs_fuse_fill_security_context(req, &security); +#endif + ni = ntfs_inode_open(ctx->vol, INODE(ino)); + if (!ni) { + ret = -errno; + goto out; + } +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + /* file must be readable */ +// condition on fill_security ? + if (!ntfs_allowed_access(&security,ni,S_IREAD)) { + ret = -EACCES; + goto exit; + } +#endif + actx = ntfs_attr_get_search_ctx(ni, NULL); + if (!actx) { + ret = -errno; + goto exit; + } + if (size) { + list = (char*)malloc(size); + if (!list) { + ret = -errno; + goto exit; + } + } + to = list; + + if ((ctx->streams == NF_STREAMS_INTERFACE_XATTR) + || (ctx->streams == NF_STREAMS_INTERFACE_OPENXATTR)) { + while (!ntfs_attr_lookup(AT_DATA, NULL, 0, CASE_SENSITIVE, + 0, NULL, 0, actx)) { + char *tmp_name = NULL; + int tmp_name_len; + + if (!actx->attr->name_length) + continue; + tmp_name_len = ntfs_ucstombs( + (ntfschar *)((u8*)actx->attr + + le16_to_cpu(actx->attr->name_offset)), + actx->attr->name_length, &tmp_name, 0); + if (tmp_name_len < 0) { + ret = -errno; + goto exit; + } + /* + * When using name spaces, do not return + * security, trusted nor system attributes + * (filtered elsewhere anyway) + * otherwise insert "user." prefix + */ + if (ctx->streams == NF_STREAMS_INTERFACE_XATTR) { + if ((strlen(tmp_name) > sizeof(xattr_ntfs_3g)) + && !strncmp(tmp_name,xattr_ntfs_3g, + sizeof(xattr_ntfs_3g)-1)) + tmp_name_len = 0; + else + ret += tmp_name_len + + nf_ns_user_prefix_len + 1; + } else + ret += tmp_name_len + 1; + if (size && tmp_name_len) { + if ((size_t)ret <= size) { + if (ctx->streams + == NF_STREAMS_INTERFACE_XATTR) { + strcpy(to, nf_ns_user_prefix); + to += nf_ns_user_prefix_len; + } + strncpy(to, tmp_name, tmp_name_len); + to += tmp_name_len; + *to = 0; + to++; + } else { + free(tmp_name); + ret = -ERANGE; + goto exit; + } + } + free(tmp_name); + } + } + + /* List efs info xattr for encrypted files */ + if (ctx->efs_raw && (ni->flags & FILE_ATTR_ENCRYPTED)) { + ret += sizeof(nf_ns_xattr_efsinfo); + if ((size_t)ret <= size) { + memcpy(to, nf_ns_xattr_efsinfo, + sizeof(nf_ns_xattr_efsinfo)); + to += sizeof(nf_ns_xattr_efsinfo); + } + } + + if (errno != ENOENT) + ret = -errno; +exit: + if (actx) + ntfs_attr_put_search_ctx(actx); + if (ntfs_inode_close(ni)) + set_fuse_error(&ret); +out : + if (ret < 0) + fuse_reply_err(req, -ret); + else + if (size) + fuse_reply_buf(req, list, ret); + else + fuse_reply_xattr(req, ret); + free(list); +} + +static __inline__ int ntfs_system_getxattr(struct SECURITY_CONTEXT *scx, + int attr, ntfs_inode *ni, char *value, size_t size) +{ + int res; + ntfs_inode *dir_ni; + + /* + * the returned value is the needed + * size. If it is too small, no copy + * is done, and the caller has to + * issue a new call with correct size. + */ + switch (attr) { + case XATTR_NTFS_ACL : + res = ntfs_get_ntfs_acl(scx, ni, value, size); + break; +#if POSIXACLS + case XATTR_POSIX_ACC : + res = ntfs_get_posix_acl(scx, ni, nf_ns_xattr_posix_access, + value, size); + break; + case XATTR_POSIX_DEF : + res = ntfs_get_posix_acl(scx, ni, nf_ns_xattr_posix_default, + value, size); + break; +#endif + case XATTR_NTFS_ATTRIB : + res = ntfs_get_ntfs_attrib(ni, value, size); + break; + case XATTR_NTFS_EFSINFO : + if (ctx->efs_raw) + res = ntfs_get_efs_info(ni, value, size); + else + res = -EPERM; + break; + case XATTR_NTFS_REPARSE_DATA : + res = ntfs_get_ntfs_reparse_data(ni, value, size); + break; + case XATTR_NTFS_OBJECT_ID : + res = ntfs_get_ntfs_object_id(ni, value, size); + break; + case XATTR_NTFS_DOS_NAME: + dir_ni = ntfs_dir_parent_inode(ni); + if (dir_ni) { + res = ntfs_get_ntfs_dos_name(ni, dir_ni, value, size); + if (ntfs_inode_close(dir_ni)) + set_fuse_error(&res); + } else + res = -errno; + break; + case XATTR_NTFS_TIMES: + res = ntfs_inode_get_times(ni, value, size); + break; + default : + errno = EOPNOTSUPP; + res = -errno; + break; + } + return (res); +} + +static void ntfs_fuse_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name, + size_t size) +{ + ntfs_inode *ni; + ntfs_attr *na = NULL; + char *value = (char*)NULL; + ntfschar *lename = (ntfschar*)NULL; + int lename_len; + int res; + s64 rsize; + int attr; + int namespace; + struct SECURITY_CONTEXT security; + + attr = mapped_xattr_system(name); + if (attr != XATTR_UNMAPPED) { + /* + * hijack internal data and ACL retrieval, whatever + * mode was selected for xattr (from the user's + * point of view, ACLs are not xattr) + */ + if (size) + value = (char*)ntfs_malloc(size); +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + if (!size || value) { + ni = ntfs_check_access_xattr(req, &security, ino, + attr, FALSE); + if (ni) { + if (ntfs_allowed_access(&security,ni,S_IREAD)) + res = ntfs_system_getxattr(&security, + attr, ni, value, size); + else + res = -errno; + if (ntfs_inode_close(ni)) + set_fuse_error(&res); + } else + res = -errno; + } +#else + /* + * Standard access control has been done by fuse/kernel + */ + if (!size || value) { + ni = ntfs_inode_open(ctx->vol, INODE(ino)); + if (ni) { + /* user mapping not mandatory */ + ntfs_fuse_fill_security_context(req, &security); + res = ntfs_system_getxattr(&security, + attr, ni, value, size); + if (ntfs_inode_close(ni)) + set_fuse_error(&res); + } else + res = -errno; + } else + res = -errno; +#endif + if (res < 0) + fuse_reply_err(req, -res); + else + if (size) + fuse_reply_buf(req, value, res); + else + fuse_reply_xattr(req, res); + free(value); + return; + } + if (ctx->streams == NF_STREAMS_INTERFACE_NONE) { + res = -EOPNOTSUPP; + goto out; + } + if (ctx->streams == NF_STREAMS_INTERFACE_NONE) { + res = -EOPNOTSUPP; + goto out; + } + namespace = xattr_namespace(name); + if (namespace == XATTRNS_NONE) { + res = -EOPNOTSUPP; + goto out; + } +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + ntfs_fuse_fill_security_context(req,&security); + /* trusted only readable by root */ + if ((namespace == XATTRNS_TRUSTED) + && security.uid) { + res = -EPERM; + goto out; + } +#endif + ni = ntfs_inode_open(ctx->vol, INODE(ino)); + if (!ni) { + res = -errno; + goto out; + } +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + /* file must be readable */ +// condition on fill_security + if (!ntfs_allowed_access(&security, ni, S_IREAD)) { + res = -errno; + goto exit; + } +#endif + lename_len = fix_xattr_prefix(name, namespace, &lename); + if (lename_len == -1) { + res = -errno; + goto exit; + } + na = ntfs_attr_open(ni, AT_DATA, lename, lename_len); + if (!na) { + res = -ENODATA; + goto exit; + } + rsize = na->data_size; + if (ctx->efs_raw && + (na->data_flags & ATTR_IS_ENCRYPTED) && + NAttrNonResident(na)) + rsize = ((na->data_size + 511) & ~511)+2; + if (size) { + if (size >= (size_t)rsize) { + value = (char*)ntfs_malloc(rsize); + if (value) + res = ntfs_attr_pread(na, 0, rsize, value); + if (!value || (res != rsize)) + res = -errno; + } else + res = -ERANGE; + } else + res = rsize; +exit: + if (na) + ntfs_attr_close(na); + free(lename); + if (ntfs_inode_close(ni)) + set_fuse_error(&res); + +out : + if (res < 0) + fuse_reply_err(req, -res); + else + if (size) + fuse_reply_buf(req, value, res); + else + fuse_reply_xattr(req, res); + free(value); +} + +static __inline__ int ntfs_system_setxattr(struct SECURITY_CONTEXT *scx, + int attr, ntfs_inode *ni, const char *value, + size_t size, int flags) +{ + int res; + ntfs_inode *dir_ni; + + switch (attr) { + case XATTR_NTFS_ACL : + res = ntfs_set_ntfs_acl(scx, ni, value, size, flags); + break; +#if POSIXACLS + case XATTR_POSIX_ACC : + res = ntfs_set_posix_acl(scx ,ni , nf_ns_xattr_posix_access, + value, size, flags); + break; + case XATTR_POSIX_DEF : + res = ntfs_set_posix_acl(scx, ni, nf_ns_xattr_posix_default, + value, size, flags); + break; +#endif + case XATTR_NTFS_ATTRIB : + res = ntfs_set_ntfs_attrib(ni, value, size, flags); + break; + case XATTR_NTFS_EFSINFO : + if (ctx->efs_raw) + res = ntfs_set_efs_info(ni, value, size, flags); + else + res = -EPERM; + break; + case XATTR_NTFS_REPARSE_DATA : + res = ntfs_set_ntfs_reparse_data(ni, value, size, flags); + break; + case XATTR_NTFS_OBJECT_ID : + res = ntfs_set_ntfs_object_id(ni, value, size, flags); + break; + case XATTR_NTFS_DOS_NAME: + dir_ni = ntfs_dir_parent_inode(ni); + if (dir_ni) + /* warning : this closes both inodes */ + res = ntfs_set_ntfs_dos_name(ni, dir_ni, value, + size, flags); + else + res = -errno; + break; + case XATTR_NTFS_TIMES: + res = ntfs_inode_set_times(ni, value, size, flags); + break; + default : + errno = EOPNOTSUPP; + res = -errno; + break; + } + return (res); +} + +static void ntfs_fuse_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name, + const char *value, size_t size, int flags) +{ + ntfs_inode *ni; + ntfs_attr *na = NULL; + ntfschar *lename = NULL; + int res, lename_len; + size_t part, total; + int attr; + int namespace; + struct SECURITY_CONTEXT security; + + attr = mapped_xattr_system(name); + if (attr != XATTR_UNMAPPED) { + /* + * hijack internal data and ACL setting, whatever + * mode was selected for xattr (from the user's + * point of view, ACLs are not xattr) + * Note : updating an ACL does not set ctime + */ +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + ni = ntfs_check_access_xattr(req,&security,ino,attr,TRUE); + if (ni) { + if (ntfs_allowed_as_owner(&security, ni)) { + res = ntfs_system_setxattr(&security, + attr, ni, value, size, flags); + if (res) + res = -errno; + } else + res = -errno; + if ((attr != XATTR_NTFS_DOS_NAME) + && ntfs_inode_close(ni)) + set_fuse_error(&res); + } else + res = -errno; +#else + /* creation of a new name is not controlled by fuse */ + if (attr == XATTR_NTFS_DOS_NAME) + ni = ntfs_check_access_xattr(req, &security, + ino, attr, TRUE); + else + ni = ntfs_inode_open(ctx->vol, INODE(ino)); + if (ni) { + /* + * user mapping is not mandatory + * if defined, only owner is allowed + */ + if (!ntfs_fuse_fill_security_context(req, &security) + || ntfs_allowed_as_owner(&security, ni)) { + res = ntfs_system_setxattr(&security, + attr, ni, value, size, flags); + if (res) + res = -errno; + } else + res = -errno; + if ((attr != XATTR_NTFS_DOS_NAME) + && ntfs_inode_close(ni)) + set_fuse_error(&res); + } else + res = -errno; +#endif + if (res < 0) + fuse_reply_err(req, -res); + else + fuse_reply_err(req, 0); + return; + } + if ((ctx->streams != NF_STREAMS_INTERFACE_XATTR) + && (ctx->streams != NF_STREAMS_INTERFACE_OPENXATTR)) { + res = -EOPNOTSUPP; + goto out; + } + namespace = xattr_namespace(name); + if (namespace == XATTRNS_NONE) { + res = -EOPNOTSUPP; + goto out; + } +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + ntfs_fuse_fill_security_context(req,&security); + /* security and trusted only settable by root */ + if (((namespace == XATTRNS_SECURITY) + || (namespace == XATTRNS_TRUSTED)) + && security.uid) { + res = -EPERM; + goto out; + } +#endif + ni = ntfs_inode_open(ctx->vol, INODE(ino)); + if (!ni) { + res = -errno; + goto out; + } +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + switch (namespace) { + case XATTRNS_SECURITY : + case XATTRNS_TRUSTED : + if (security.uid) { + res = -EPERM; + goto exit; + } + break; + case XATTRNS_SYSTEM : + if (!ntfs_allowed_as_owner(&security, ni)) { + res = -EACCES; + goto exit; + } + break; + default : + if (!ntfs_allowed_access(&security,ni,S_IWRITE)) { + res = -EACCES; + goto exit; + } + break; + } +#endif + lename_len = fix_xattr_prefix(name, namespace, &lename); + if (lename_len == -1) { + res = -errno; + goto exit; + } + na = ntfs_attr_open(ni, AT_DATA, lename, lename_len); + if (na && flags == XATTR_CREATE) { + res = -EEXIST; + goto exit; + } + if (!na) { + if (flags == XATTR_REPLACE) { + res = -ENODATA; + goto exit; + } + if (ntfs_attr_add(ni, AT_DATA, lename, lename_len, NULL, 0)) { + res = -errno; + goto exit; + } + if (!(ni->flags & FILE_ATTR_ARCHIVE)) { + set_archive(ni); + NInoFileNameSetDirty(ni); + } + na = ntfs_attr_open(ni, AT_DATA, lename, lename_len); + if (!na) { + res = -errno; + goto exit; + } + } else { + /* currently compressed streams can only be wiped out */ + if (ntfs_attr_truncate(na, (s64)0 /* size */)) { + res = -errno; + goto exit; + } + } + total = 0; + if (size) { + do { + part = ntfs_attr_pwrite(na, total, size - total, + &value[total]); + if (part > 0) + total += part; + } while ((part > 0) && (total < size)); + if (total != size) + res = -errno; + else + if (!(res = ntfs_attr_pclose(na))) + if (ctx->efs_raw + && (ni->flags & FILE_ATTR_ENCRYPTED)) + res = ntfs_efs_fixup_attribute(NULL, + na); + if (total && !(ni->flags & FILE_ATTR_ARCHIVE)) { + set_archive(ni); + NInoFileNameSetDirty(ni); + } + } else + res = 0; +exit: + if (na) + ntfs_attr_close(na); + free(lename); + if (ntfs_inode_close(ni)) + set_fuse_error(&res); +out : + if (res < 0) + fuse_reply_err(req, -res); + else + fuse_reply_err(req, 0); +} + +static __inline__ int ntfs_system_removexattr(fuse_req_t req, fuse_ino_t ino, + int attr) +{ + int res; + ntfs_inode *dir_ni; + ntfs_inode *ni; + struct SECURITY_CONTEXT security; + + res = 0; + switch (attr) { + /* + * Removal of NTFS ACL, ATTRIB, EFSINFO or TIMES + * is never allowed + */ + case XATTR_NTFS_ACL : + case XATTR_NTFS_ATTRIB : + case XATTR_NTFS_EFSINFO : + case XATTR_NTFS_TIMES : + res = -EPERM; + break; +#if POSIXACLS + case XATTR_POSIX_ACC : + case XATTR_POSIX_DEF : + ni = ntfs_check_access_xattr(req,&security,ino,attr,TRUE); + if (ni) { + if (!ntfs_allowed_as_owner(&security, ni) + || ntfs_remove_posix_acl(&security, ni, + (attr == XATTR_POSIX_ACC ? + nf_ns_xattr_posix_access : + nf_ns_xattr_posix_default))) + res = -errno; + if (ntfs_inode_close(ni)) + set_fuse_error(&res); + } else + res = -errno; + break; +#endif + case XATTR_NTFS_REPARSE_DATA : + ni = ntfs_check_access_xattr(req, &security, ino, attr, TRUE); + if (ni) { + if (!ntfs_allowed_as_owner(&security, ni) + || ntfs_remove_ntfs_reparse_data(ni)) + res = -errno; + if (ntfs_inode_close(ni)) + set_fuse_error(&res); + } else + res = -errno; + break; + case XATTR_NTFS_OBJECT_ID : + ni = ntfs_check_access_xattr(req, &security, ino, attr, TRUE); + if (ni) { + if (!ntfs_allowed_as_owner(&security, ni) + || ntfs_remove_ntfs_object_id(ni)) + res = -errno; + if (ntfs_inode_close(ni)) + set_fuse_error(&res); + } else + res = -errno; + break; + case XATTR_NTFS_DOS_NAME: + ni = ntfs_check_access_xattr(req,&security,ino,attr,TRUE); + if (ni) { + dir_ni = ntfs_dir_parent_inode(ni); + if (!dir_ni + || ntfs_remove_ntfs_dos_name(ni,dir_ni)) + res = -errno; + } else + res = -errno; + break; + default : + errno = EOPNOTSUPP; + res = -errno; + break; + } + return (res); +} + +static void ntfs_fuse_removexattr(fuse_req_t req, fuse_ino_t ino, const char *name) +{ + ntfs_inode *ni; + ntfschar *lename = NULL; + int res = 0, lename_len; + int attr; + int namespace; +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + struct SECURITY_CONTEXT security; +#endif + + attr = mapped_xattr_system(name); + if (attr != XATTR_UNMAPPED) { + /* + * hijack internal data and ACL removal, whatever + * mode was selected for xattr (from the user's + * point of view, ACLs are not xattr) + * Note : updating an ACL does not set ctime + */ + res = ntfs_system_removexattr(req, ino, attr); + if (res < 0) + fuse_reply_err(req, -res); + else + fuse_reply_err(req, 0); + return; + } + if ((ctx->streams != NF_STREAMS_INTERFACE_XATTR) + && (ctx->streams != NF_STREAMS_INTERFACE_OPENXATTR)) { + res = -EOPNOTSUPP; + goto out; + } + namespace = xattr_namespace(name); + if (namespace == XATTRNS_NONE) { + res = -EOPNOTSUPP; + goto out; + } +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + ntfs_fuse_fill_security_context(req,&security); + /* security and trusted only settable by root */ + if (((namespace == XATTRNS_SECURITY) + || (namespace == XATTRNS_TRUSTED)) + && security.uid) { + res = -EACCES; + goto out; + } +#endif + ni = ntfs_inode_open(ctx->vol, INODE(ino)); + if (!ni) { + res = -errno; + goto out; + } +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + switch (namespace) { + case XATTRNS_SECURITY : + case XATTRNS_TRUSTED : + if (security.uid) { + res = -EPERM; + goto exit; + } + break; + case XATTRNS_SYSTEM : + if (!ntfs_allowed_as_owner(&security, ni)) { + res = -EACCES; + goto exit; + } + break; + default : + if (!ntfs_allowed_access(&security,ni,S_IWRITE)) { + res = -EACCES; + goto exit; + } + break; + } +#endif + lename_len = fix_xattr_prefix(name, namespace, &lename); + if (lename_len == -1) { + res = -errno; + goto exit; + } + if (ntfs_attr_remove(ni, AT_DATA, lename, lename_len)) { + if (errno == ENOENT) + errno = ENODATA; + res = -errno; + } + if (!(ni->flags & FILE_ATTR_ARCHIVE)) { + set_archive(ni); + NInoFileNameSetDirty(ni); + } +exit: + free(lename); + if (ntfs_inode_close(ni)) + set_fuse_error(&res); +out : + if (res < 0) + fuse_reply_err(req, -res); + else + fuse_reply_err(req, 0); + return; + +} + +#else +#if POSIXACLS +#error "Option inconsistency : POSIXACLS requires SETXATTR" +#endif +#endif /* HAVE_SETXATTR */ + +static void ntfs_close(void) +{ + struct SECURITY_CONTEXT security; + + if (!ctx) + return; + + if (!ctx->vol) + return; + + if (ctx->mounted) { + ntfs_log_info("Unmounting %s (%s)\n", opts.device, + ctx->vol->vol_name); + if (ntfs_fuse_fill_security_context((fuse_req_t)NULL, &security)) { + if (ctx->seccache && ctx->seccache->head.p_reads) { + ntfs_log_info("Permissions cache : %lu writes, " + "%lu reads, %lu.%1lu%% hits\n", + ctx->seccache->head.p_writes, + ctx->seccache->head.p_reads, + 100 * ctx->seccache->head.p_hits + / ctx->seccache->head.p_reads, + 1000 * ctx->seccache->head.p_hits + / ctx->seccache->head.p_reads % 10); + } + } + ntfs_close_secure(&security); + } + + if (ntfs_umount(ctx->vol, FALSE)) + ntfs_log_perror("Failed to close volume %s", opts.device); + + ctx->vol = NULL; +} + +static void ntfs_fuse_destroy2(void *notused __attribute__((unused))) +{ + ntfs_close(); +} + +static struct fuse_lowlevel_ops ntfs_3g_ops = { + .lookup = ntfs_fuse_lookup, + .getattr = ntfs_fuse_getattr, + .readlink = ntfs_fuse_readlink, + .opendir = ntfs_fuse_opendir, + .readdir = ntfs_fuse_readdir, + .releasedir = ntfs_fuse_releasedir, + .open = ntfs_fuse_open, + .release = ntfs_fuse_release, + .read = ntfs_fuse_read, + .write = ntfs_fuse_write, + .setattr = ntfs_fuse_setattr, + .statfs = ntfs_fuse_statfs, + .create = ntfs_fuse_create_file, + .mknod = ntfs_fuse_mknod, + .symlink = ntfs_fuse_symlink, + .link = ntfs_fuse_link, + .unlink = ntfs_fuse_unlink, + .rename = ntfs_fuse_rename, + .mkdir = ntfs_fuse_mkdir, + .rmdir = ntfs_fuse_rmdir, + .bmap = ntfs_fuse_bmap, + .destroy = ntfs_fuse_destroy2, +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + .access = ntfs_fuse_access, +#endif +#ifdef HAVE_SETXATTR + .getxattr = ntfs_fuse_getxattr, + .setxattr = ntfs_fuse_setxattr, + .removexattr = ntfs_fuse_removexattr, + .listxattr = ntfs_fuse_listxattr, +#endif /* HAVE_SETXATTR */ +#if 0 && (defined(__APPLE__) || defined(__DARWIN__)) /* Unfinished. */ + /* MacFUSE extensions. */ + .getxtimes = ntfs_macfuse_getxtimes, + .setcrtime = ntfs_macfuse_setcrtime, + .setbkuptime = ntfs_macfuse_setbkuptime, + .setchgtime = ntfs_macfuse_setchgtime, +#endif /* defined(__APPLE__) || defined(__DARWIN__) */ +#if defined(FUSE_CAP_DONT_MASK) || (defined(__APPLE__) || defined(__DARWIN__)) + .init = ntfs_init +#endif +}; + +static int ntfs_fuse_init(void) +{ + ctx = (ntfs_fuse_context_t*)ntfs_calloc(sizeof(ntfs_fuse_context_t)); + if (!ctx) + return -1; + + *ctx = (ntfs_fuse_context_t) { + .uid = getuid(), + .gid = getgid(), +#if defined(linux) + .streams = NF_STREAMS_INTERFACE_XATTR, +#else + .streams = NF_STREAMS_INTERFACE_NONE, +#endif + .atime = ATIME_RELATIVE, + .silent = TRUE, + .recover = TRUE + }; + return 0; +} + +static int ntfs_open(const char *device) +{ + unsigned long flags = 0; + + if (!ctx->blkdev) + flags |= MS_EXCLUSIVE; + if (ctx->ro) + flags |= MS_RDONLY; + if (ctx->recover) + flags |= MS_RECOVER; + if (ctx->hiberfile) + flags |= MS_IGNORE_HIBERFILE; + + ctx->vol = ntfs_mount(device, flags); + if (!ctx->vol) { + ntfs_log_perror("Failed to mount '%s'", device); + goto err_out; + } + + ctx->vol->free_clusters = ntfs_attr_get_free_bits(ctx->vol->lcnbmp_na); + if (ctx->vol->free_clusters < 0) { + ntfs_log_perror("Failed to read NTFS $Bitmap"); + goto err_out; + } + + ctx->vol->free_mft_records = ntfs_get_nr_free_mft_records(ctx->vol); + if (ctx->vol->free_mft_records < 0) { + ntfs_log_perror("Failed to calculate free MFT records"); + goto err_out; + } + + if (ctx->hiberfile && ntfs_volume_check_hiberfile(ctx->vol, 0)) { + if (errno != EPERM) + goto err_out; + if (ntfs_fuse_rm((fuse_req_t)NULL,FILE_root,"hiberfil.sys")) + goto err_out; + } + + errno = 0; +err_out: + return ntfs_volume_error(errno); + +} + +#define STRAPPEND_MAX_INSIZE 8192 +#define strappend_is_large(x) ((x) > STRAPPEND_MAX_INSIZE) + +static int strappend(char **dest, const char *append) +{ + char *p; + size_t size_append, size_dest = 0; + + if (!dest) + return -1; + if (!append) + return 0; + + size_append = strlen(append); + if (*dest) + size_dest = strlen(*dest); + + if (strappend_is_large(size_dest) || strappend_is_large(size_append)) { + errno = EOVERFLOW; + ntfs_log_perror("%s: Too large input buffer", EXEC_NAME); + return -1; + } + + p = (char*)realloc(*dest, size_dest + size_append + 1); + if (!p) { + ntfs_log_perror("%s: Memory reallocation failed", EXEC_NAME); + return -1; + } + + *dest = p; + strcpy(*dest + size_dest, append); + + return 0; +} + +static int bogus_option_value(char *val, const char *s) +{ + if (val) { + ntfs_log_error("'%s' option shouldn't have value.\n", s); + return -1; + } + return 0; +} + +static int missing_option_value(char *val, const char *s) +{ + if (!val) { + ntfs_log_error("'%s' option should have a value.\n", s); + return -1; + } + return 0; +} + +static char *parse_mount_options(const char *orig_opts) +{ + char *options, *s, *opt, *val, *ret = NULL; + BOOL no_def_opts = FALSE; + int default_permissions = 0; + int want_permissions = 0; + + ctx->secure_flags = 0; +#ifdef HAVE_SETXATTR /* extended attributes interface required */ + ctx->efs_raw = FALSE; +#endif /* HAVE_SETXATTR */ + options = strdup(orig_opts ? orig_opts : ""); + if (!options) { + ntfs_log_perror("%s: strdup failed", EXEC_NAME); + return NULL; + } + + s = options; + while (s && *s && (val = strsep(&s, ","))) { + opt = strsep(&val, "="); + if (!strcmp(opt, "ro")) { /* Read-only mount. */ + if (bogus_option_value(val, "ro")) + goto err_exit; + ctx->ro = TRUE; + if (strappend(&ret, "ro,")) + goto err_exit; + } else if (!strcmp(opt, "noatime")) { + if (bogus_option_value(val, "noatime")) + goto err_exit; + ctx->atime = ATIME_DISABLED; + } else if (!strcmp(opt, "atime")) { + if (bogus_option_value(val, "atime")) + goto err_exit; + ctx->atime = ATIME_ENABLED; + } else if (!strcmp(opt, "relatime")) { + if (bogus_option_value(val, "relatime")) + goto err_exit; + ctx->atime = ATIME_RELATIVE; + } else if (!strcmp(opt, "fake_rw")) { + if (bogus_option_value(val, "fake_rw")) + goto err_exit; + ctx->ro = TRUE; + } else if (!strcmp(opt, "fsname")) { /* Filesystem name. */ + /* + * We need this to be able to check whether filesystem + * mounted or not. + */ + ntfs_log_error("'fsname' is unsupported option.\n"); + goto err_exit; + } else if (!strcmp(opt, "no_def_opts")) { + if (bogus_option_value(val, "no_def_opts")) + goto err_exit; + no_def_opts = TRUE; /* Don't add default options. */ + } else if (!strcmp(opt, "default_permissions")) { + default_permissions = 1; + } else if (!strcmp(opt, "umask")) { + if (missing_option_value(val, "umask")) + goto err_exit; + sscanf(val, "%o", &ctx->fmask); + ctx->dmask = ctx->fmask; + want_permissions = 1; + } else if (!strcmp(opt, "fmask")) { + if (missing_option_value(val, "fmask")) + goto err_exit; + sscanf(val, "%o", &ctx->fmask); + want_permissions = 1; + } else if (!strcmp(opt, "dmask")) { + if (missing_option_value(val, "dmask")) + goto err_exit; + sscanf(val, "%o", &ctx->dmask); + want_permissions = 1; + } else if (!strcmp(opt, "uid")) { + if (missing_option_value(val, "uid")) + goto err_exit; + sscanf(val, "%i", &ctx->uid); + want_permissions = 1; + } else if (!strcmp(opt, "gid")) { + if (missing_option_value(val, "gid")) + goto err_exit; + sscanf(val, "%i", &ctx->gid); + want_permissions = 1; + } else if (!strcmp(opt, "show_sys_files")) { + if (bogus_option_value(val, "show_sys_files")) + goto err_exit; + ctx->show_sys_files = TRUE; + } else if (!strcmp(opt, "silent")) { + if (bogus_option_value(val, "silent")) + goto err_exit; + ctx->silent = TRUE; + } else if (!strcmp(opt, "recover")) { + if (bogus_option_value(val, "recover")) + goto err_exit; + ctx->recover = TRUE; + } else if (!strcmp(opt, "norecover")) { + if (bogus_option_value(val, "norecover")) + goto err_exit; + ctx->recover = FALSE; + } else if (!strcmp(opt, "remove_hiberfile")) { + if (bogus_option_value(val, "remove_hiberfile")) + goto err_exit; + ctx->hiberfile = TRUE; + } else if (!strcmp(opt, "locale")) { + if (missing_option_value(val, "locale")) + goto err_exit; + ntfs_set_char_encoding(val); +#if defined(__APPLE__) || defined(__DARWIN__) +#ifdef ENABLE_NFCONV + } else if (!strcmp(opt, "nfconv")) { + if (bogus_option_value(val, "nfconv")) + goto err_exit; + if (ntfs_macosx_normalize_filenames(1)) { + ntfs_log_error("ntfs_macosx_normalize_filenames(1) failed!\n"); + goto err_exit; + } + } else if (!strcmp(opt, "nonfconv")) { + if (bogus_option_value(val, "nonfconv")) + goto err_exit; + if (ntfs_macosx_normalize_filenames(0)) { + ntfs_log_error("ntfs_macosx_normalize_filenames(0) failed!\n"); + goto err_exit; + } +#endif /* ENABLE_NFCONV */ +#endif /* defined(__APPLE__) || defined(__DARWIN__) */ + } else if (!strcmp(opt, "streams_interface")) { + if (missing_option_value(val, "streams_interface")) + goto err_exit; + if (!strcmp(val, "none")) + ctx->streams = NF_STREAMS_INTERFACE_NONE; + else if (!strcmp(val, "xattr")) + ctx->streams = NF_STREAMS_INTERFACE_XATTR; + else if (!strcmp(val, "openxattr")) + ctx->streams = NF_STREAMS_INTERFACE_OPENXATTR; + else { + ntfs_log_error("Invalid named data streams " + "access interface.\n"); + goto err_exit; + } + } else if (!strcmp(opt, "user_xattr")) { + ctx->streams = NF_STREAMS_INTERFACE_XATTR; + } else if (!strcmp(opt, "noauto")) { + /* Don't pass noauto option to fuse. */ + } else if (!strcmp(opt, "debug")) { + if (bogus_option_value(val, "debug")) + goto err_exit; + ctx->debug = TRUE; + ntfs_log_set_levels(NTFS_LOG_LEVEL_DEBUG); + ntfs_log_set_levels(NTFS_LOG_LEVEL_TRACE); + } else if (!strcmp(opt, "no_detach")) { + if (bogus_option_value(val, "no_detach")) + goto err_exit; + ctx->no_detach = TRUE; + } else if (!strcmp(opt, "remount")) { + ntfs_log_error("Remounting is not supported at present." + " You have to umount volume and then " + "mount it once again.\n"); + goto err_exit; + } else if (!strcmp(opt, "blksize")) { + ntfs_log_info("WARNING: blksize option is ignored " + "because ntfs-3g must calculate it.\n"); + } else if (!strcmp(opt, "inherit")) { + /* + * JPA do not overwrite inherited permissions + * in create() + */ + ctx->inherit = TRUE; + } else if (!strcmp(opt, "addsecurids")) { + /* + * JPA create security ids for files being read + * with an individual security attribute + */ + ctx->secure_flags |= (1 << SECURITY_ADDSECURIDS); + } else if (!strcmp(opt, "staticgrps")) { + /* + * JPA use static definition of groups + * for file access control + */ + ctx->secure_flags |= (1 << SECURITY_STATICGRPS); + } else if (!strcmp(opt, "usermapping")) { + if (!val) { + ntfs_log_error("'usermapping' option should have " + "a value.\n"); + goto err_exit; + } + ctx->usermap_path = strdup(val); + if (!ctx->usermap_path) { + ntfs_log_error("no more memory to store " + "'usermapping' option.\n"); + goto err_exit; + } +#ifdef HAVE_SETXATTR /* extended attributes interface required */ + } else if (!strcmp(opt, "efs_raw")) { + if (bogus_option_value(val, "efs_raw")) + goto err_exit; + ctx->efs_raw = TRUE; +#endif /* HAVE_SETXATTR */ + } else { /* Probably FUSE option. */ + if (strappend(&ret, opt)) + goto err_exit; + if (val) { + if (strappend(&ret, "=")) + goto err_exit; + if (strappend(&ret, val)) + goto err_exit; + } + if (strappend(&ret, ",")) + goto err_exit; + } + } + if (!no_def_opts && strappend(&ret, def_opts)) + goto err_exit; +#if KERNELPERMS + if (default_permissions && strappend(&ret, "default_permissions,")) + goto err_exit; +#endif + + if (ctx->atime == ATIME_RELATIVE && strappend(&ret, "relatime,")) + goto err_exit; + else if (ctx->atime == ATIME_ENABLED && strappend(&ret, "atime,")) + goto err_exit; + else if (ctx->atime == ATIME_DISABLED && strappend(&ret, "noatime,")) + goto err_exit; + + if (strappend(&ret, "fsname=")) + goto err_exit; + if (strappend(&ret, opts.device)) + goto err_exit; + if (default_permissions) + ctx->secure_flags |= (1 << SECURITY_DEFAULT); + if (want_permissions) + ctx->secure_flags |= (1 << SECURITY_WANTED); + if (ctx->ro) + ctx->secure_flags &= ~(1 << SECURITY_ADDSECURIDS); +exit: + free(options); + return ret; +err_exit: + free(ret); + ret = NULL; + goto exit; +} + +static void usage(void) +{ + ntfs_log_info(usage_msg, EXEC_NAME, VERSION, FUSE_TYPE, fuse_version(), + 5 + POSIXACLS*6 - KERNELPERMS*3 + CACHEING, + EXEC_NAME, ntfs_home); +} + +#ifndef HAVE_REALPATH +/* If there is no realpath() on the system, provide a dummy one. */ +static char *realpath(const char *path, char *resolved_path) +{ + strncpy(resolved_path, path, PATH_MAX); + resolved_path[PATH_MAX] = '\0'; + return resolved_path; +} +#endif + +/** + * parse_options - Read and validate the programs command line + * Read the command line, verify the syntax and parse the options. + * + * Return: 0 success, -1 error. + */ +static int parse_options(int argc, char *argv[]) +{ + int c; + + static const char *sopt = "-o:hvV"; + static const struct option lopt[] = { + { "options", required_argument, NULL, 'o' }, + { "help", no_argument, NULL, 'h' }, + { "verbose", no_argument, NULL, 'v' }, + { "version", no_argument, NULL, 'V' }, + { NULL, 0, NULL, 0 } + }; + + opterr = 0; /* We'll handle the errors, thank you. */ + + while ((c = getopt_long(argc, argv, sopt, lopt, NULL)) != -1) { + switch (c) { + case 1: /* A non-option argument */ + if (!opts.device) { + opts.device = (char*)ntfs_malloc(PATH_MAX + 1); + if (!opts.device) + return -1; + + /* Canonicalize device name (mtab, etc) */ + if (!realpath(optarg, opts.device)) { + ntfs_log_perror("%s: Failed to access " + "volume '%s'", EXEC_NAME, optarg); + free(opts.device); + opts.device = NULL; + return -1; + } + } else if (!opts.mnt_point) { + opts.mnt_point = optarg; + } else { + ntfs_log_error("%s: You must specify exactly one " + "device and exactly one mount " + "point.\n", EXEC_NAME); + return -1; + } + break; + case 'o': + if (opts.options) + if (strappend(&opts.options, ",")) + return -1; + if (strappend(&opts.options, optarg)) + return -1; + break; + case 'h': + usage(); + exit(9); + case 'v': + /* + * We must handle the 'verbose' option even if + * we don't use it because mount(8) passes it. + */ + break; + case 'V': + ntfs_log_info("%s %s %s %d\n", EXEC_NAME, VERSION, + FUSE_TYPE, fuse_version()); + exit(0); + default: + ntfs_log_error("%s: Unknown option '%s'.\n", EXEC_NAME, + argv[optind - 1]); + return -1; + } + } + + if (!opts.device) { + ntfs_log_error("%s: No device is specified.\n", EXEC_NAME); + return -1; + } + if (!opts.mnt_point) { + ntfs_log_error("%s: No mountpoint is specified.\n", EXEC_NAME); + return -1; + } + + return 0; +} + +#if defined(linux) || defined(__uClinux__) + +static const char *dev_fuse_msg = +"HINT: You should be root, or make ntfs-3g setuid root, or load the FUSE\n" +" kernel module as root ('modprobe fuse' or 'insmod /fuse.ko'" +" or insmod /fuse.o'). Make also sure that the fuse device" +" exists. It's usually either /dev/fuse or /dev/misc/fuse."; + +static const char *fuse26_kmod_msg = +"WARNING: Deficient Linux kernel detected. Some driver features are\n" +" not available (swap file on NTFS, boot from NTFS by LILO), and\n" +" unmount is not safe unless it's made sure the ntfs-3g process\n" +" naturally terminates after calling 'umount'. If you wish this\n" +" message to disappear then you should upgrade to at least kernel\n" +" version 2.6.20, or request help from your distribution to fix\n" +" the kernel problem. The below web page has more information:\n" +" http://ntfs-3g.org/support.html#fuse26\n" +"\n"; + +static void mknod_dev_fuse(const char *dev) +{ + struct stat st; + + if (stat(dev, &st) && (errno == ENOENT)) { + mode_t mask = umask(0); + if (mknod(dev, S_IFCHR | 0666, makedev(10, 229))) { + ntfs_log_perror("Failed to create '%s'", dev); + if (errno == EPERM) + ntfs_log_error("%s", dev_fuse_msg); + } + umask(mask); + } +} + +static void create_dev_fuse(void) +{ + mknod_dev_fuse("/dev/fuse"); + +#ifdef __UCLIBC__ + { + struct stat st; + /* The fuse device is under /dev/misc using devfs. */ + if (stat("/dev/misc", &st) && (errno == ENOENT)) { + mode_t mask = umask(0); + mkdir("/dev/misc", 0775); + umask(mask); + } + mknod_dev_fuse("/dev/misc/fuse"); + } +#endif +} + +static fuse_fstype get_fuse_fstype(void) +{ + char buf[256]; + fuse_fstype fstype = FSTYPE_NONE; + + FILE *f = fopen("/proc/filesystems", "r"); + if (!f) { + ntfs_log_perror("Failed to open /proc/filesystems"); + return FSTYPE_UNKNOWN; + } + + while (fgets(buf, sizeof(buf), f)) { + if (strstr(buf, "fuseblk\n")) { + fstype = FSTYPE_FUSEBLK; + break; + } + if (strstr(buf, "fuse\n")) + fstype = FSTYPE_FUSE; + } + + fclose(f); + return fstype; +} + +static fuse_fstype load_fuse_module(void) +{ + int i; + struct stat st; + pid_t pid; + const char *cmd = "/sbin/modprobe"; + struct timespec req = { 0, 100000000 }; /* 100 msec */ + fuse_fstype fstype; + + if (!stat(cmd, &st) && !geteuid()) { + pid = fork(); + if (!pid) { + execl(cmd, cmd, "fuse", NULL); + _exit(1); + } else if (pid != -1) + waitpid(pid, NULL, 0); + } + + for (i = 0; i < 10; i++) { + /* + * We sleep first because despite the detection of the loaded + * FUSE kernel module, fuse_mount() can still fail if it's not + * fully functional/initialized. Note, of course this is still + * unreliable but usually helps. + */ + nanosleep(&req, NULL); + fstype = get_fuse_fstype(); + if (fstype != FSTYPE_NONE) + break; + } + return fstype; +} + +#endif + +static struct fuse_chan *try_fuse_mount(char *parsed_options) +{ + struct fuse_chan *fc = NULL; + struct fuse_args margs = FUSE_ARGS_INIT(0, NULL); + + /* The fuse_mount() options get modified, so we always rebuild it */ + if ((fuse_opt_add_arg(&margs, EXEC_NAME) == -1 || + fuse_opt_add_arg(&margs, "-o") == -1 || + fuse_opt_add_arg(&margs, parsed_options) == -1)) { + ntfs_log_error("Failed to set FUSE options.\n"); + goto free_args; + } + + fc = fuse_mount(opts.mnt_point, &margs); +free_args: + fuse_opt_free_args(&margs); + return fc; + +} + +static int set_fuseblk_options(char **parsed_options) +{ + char options[64]; + long pagesize; + u32 blksize = ctx->vol->cluster_size; + + pagesize = sysconf(_SC_PAGESIZE); + if (pagesize < 1) + pagesize = 4096; + + if (blksize > (u32)pagesize) + blksize = pagesize; + + snprintf(options, sizeof(options), ",blkdev,blksize=%u", blksize); + if (strappend(parsed_options, options)) + return -1; + return 0; +} + +static struct fuse_session *mount_fuse(char *parsed_options) +{ + struct fuse_session *se = NULL; + struct fuse_args args = FUSE_ARGS_INIT(0, NULL); + + ctx->fc = try_fuse_mount(parsed_options); + if (!ctx->fc) + return NULL; + + if (fuse_opt_add_arg(&args, "") == -1) + goto err; + if (ctx->debug) + if (fuse_opt_add_arg(&args, "-odebug") == -1) + goto err; + + se = fuse_lowlevel_new(&args , &ntfs_3g_ops, sizeof(ntfs_3g_ops), NULL); + if (!se) + goto err; + + + if (fuse_set_signal_handlers(se)) + goto err_destroy; + fuse_session_add_chan(se, ctx->fc); +out: + fuse_opt_free_args(&args); + return se; +err_destroy: + fuse_session_destroy(se); + se = NULL; +err: + fuse_unmount(opts.mnt_point, ctx->fc); + goto out; +} + +static void setup_logging(char *parsed_options) +{ + if (!ctx->no_detach) { + if (daemon(0, ctx->debug)) + ntfs_log_error("Failed to daemonize.\n"); + else if (!ctx->debug) { +#ifndef DEBUG + ntfs_log_set_handler(ntfs_log_handler_syslog); + /* Override default libntfs identify. */ + openlog(EXEC_NAME, LOG_PID, LOG_DAEMON); +#endif + } + } + + ctx->seccache = (struct PERMISSIONS_CACHE*)NULL; + + ntfs_log_info("Version %s %s %d\n", VERSION, FUSE_TYPE, fuse_version()); + ntfs_log_info("Mounted %s (%s, label \"%s\", NTFS %d.%d)\n", + opts.device, (ctx->ro) ? "Read-Only" : "Read-Write", + ctx->vol->vol_name, ctx->vol->major_ver, + ctx->vol->minor_ver); + ntfs_log_info("Cmdline options: %s\n", opts.options ? opts.options : ""); + ntfs_log_info("Mount options: %s\n", parsed_options); +} + +int main(int argc, char *argv[]) +{ + char *parsed_options = NULL; + struct fuse_session *se; +#if !(defined(__sun) && defined (__SVR4)) + fuse_fstype fstype = FSTYPE_UNKNOWN; +#endif + const char *permissions_mode = (const char*)NULL; + const char *failed_secure = (const char*)NULL; + struct stat sbuf; + int err, fd; + + /* + * Make sure file descriptors 0, 1 and 2 are open, + * otherwise chaos would ensue. + */ + do { + fd = open("/dev/null", O_RDWR); + if (fd > 2) + close(fd); + } while (fd >= 0 && fd <= 2); + +#ifndef FUSE_INTERNAL + if ((getuid() != geteuid()) || (getgid() != getegid())) { + fprintf(stderr, "%s", setuid_msg); + return NTFS_VOLUME_INSECURE; + } +#endif + if (drop_privs()) + return NTFS_VOLUME_NO_PRIVILEGE; + + ntfs_set_locale(); + ntfs_log_set_handler(ntfs_log_handler_stderr); + + if (parse_options(argc, argv)) { + usage(); + return NTFS_VOLUME_SYNTAX_ERROR; + } + + if (ntfs_fuse_init()) { + err = NTFS_VOLUME_OUT_OF_MEMORY; + goto err2; + } + + parsed_options = parse_mount_options(opts.options); + if (!parsed_options) { + err = NTFS_VOLUME_SYNTAX_ERROR; + goto err_out; + } + + /* need absolute mount point for junctions */ + if (opts.mnt_point[0] == '/') + ctx->abs_mnt_point = strdup(opts.mnt_point); + else { + ctx->abs_mnt_point = (char*)ntfs_malloc(PATH_MAX); + if (ctx->abs_mnt_point) { + if (getcwd(ctx->abs_mnt_point, + PATH_MAX - strlen(opts.mnt_point) - 1)) { + strcat(ctx->abs_mnt_point, "/"); + strcat(ctx->abs_mnt_point, opts.mnt_point); + } + } + } + if (!ctx->abs_mnt_point) { + err = NTFS_VOLUME_OUT_OF_MEMORY; + goto err_out; + } + + ctx->security.uid = 0; + ctx->security.gid = 0; + if ((opts.mnt_point[0] == '/') + && !stat(opts.mnt_point,&sbuf)) { + /* collect owner of mount point, useful for default mapping */ + ctx->security.uid = sbuf.st_uid; + ctx->security.gid = sbuf.st_gid; + } + +#if defined(linux) || defined(__uClinux__) + fstype = get_fuse_fstype(); + + err = NTFS_VOLUME_NO_PRIVILEGE; + if (restore_privs()) + goto err_out; + + if (fstype == FSTYPE_NONE || fstype == FSTYPE_UNKNOWN) + fstype = load_fuse_module(); + create_dev_fuse(); + + if (drop_privs()) + goto err_out; +#endif + if (stat(opts.device, &sbuf)) { + ntfs_log_perror("Failed to access '%s'", opts.device); + err = NTFS_VOLUME_NO_PRIVILEGE; + goto err_out; + } + +#if !(defined(__sun) && defined (__SVR4)) + /* Always use fuseblk for block devices unless it's surely missing. */ + if (S_ISBLK(sbuf.st_mode) && (fstype != FSTYPE_FUSE)) + ctx->blkdev = TRUE; +#endif + +#ifndef FUSE_INTERNAL + if (getuid() && ctx->blkdev) { + ntfs_log_error("%s", unpriv_fuseblk_msg); + err = NTFS_VOLUME_NO_PRIVILEGE; + goto err2; + } +#endif + err = ntfs_open(opts.device); + if (err) + goto err_out; + + /* We must do this after ntfs_open() to be able to set the blksize */ + if (ctx->blkdev && set_fuseblk_options(&parsed_options)) + goto err_out; + + ctx->security.vol = ctx->vol; + ctx->vol->secure_flags = ctx->secure_flags; +#ifdef HAVE_SETXATTR /* extended attributes interface required */ + ctx->vol->efs_raw = ctx->efs_raw; +#endif /* HAVE_SETXATTR */ + /* JPA open $Secure, (whatever NTFS version !) */ + /* to initialize security data */ + if (ntfs_open_secure(ctx->vol) && (ctx->vol->major_ver >= 3)) + failed_secure = "Could not open file $Secure"; + if (!ntfs_build_mapping(&ctx->security,ctx->usermap_path)) { +#if POSIXACLS + if (ctx->vol->secure_flags & (1 << SECURITY_DEFAULT)) + permissions_mode = "User mapping built, Posix ACLs not used"; + else { + permissions_mode = "User mapping built, Posix ACLs in use"; +#if KERNELACLS + if (strappend(&parsed_options, + ",default_permissions,acl")) { + err = NTFS_VOLUME_SYNTAX_ERROR; + goto err_out; + } +#endif /* KERNELACLS */ + } +#else /* POSIXACLS */ + if (!(ctx->vol->secure_flags & (1 << SECURITY_DEFAULT))) { + /* + * No explicit option but user mapping found + * force default security + */ +#if KERNELPERMS + ctx->vol->secure_flags |= (1 << SECURITY_DEFAULT); + if (strappend(&parsed_options, ",default_permissions")) { + err = NTFS_VOLUME_SYNTAX_ERROR; + goto err_out; + } +#endif /* KERNELPERMS */ + } + permissions_mode = "User mapping built"; +#endif /* POSIXACLS */ + } else { + ctx->security.uid = ctx->uid; + ctx->security.gid = ctx->gid; + /* same ownership/permissions for all files */ + ctx->security.mapping[MAPUSERS] = (struct MAPPING*)NULL; + ctx->security.mapping[MAPGROUPS] = (struct MAPPING*)NULL; + if ((ctx->vol->secure_flags & (1 << SECURITY_WANTED)) + && !(ctx->vol->secure_flags & (1 << SECURITY_DEFAULT))) { + ctx->vol->secure_flags |= (1 << SECURITY_DEFAULT); + if (strappend(&parsed_options, ",default_permissions")) { + err = NTFS_VOLUME_SYNTAX_ERROR; + goto err_out; + } + } + if (ctx->vol->secure_flags & (1 << SECURITY_DEFAULT)) { + ctx->vol->secure_flags |= (1 << SECURITY_RAW); + permissions_mode = "Global ownership and permissions enforced"; + } else { + ctx->vol->secure_flags &= ~(1 << SECURITY_RAW); + permissions_mode = "Ownership and permissions disabled"; + } + } + if (ctx->usermap_path) + free (ctx->usermap_path); + + se = mount_fuse(parsed_options); + if (!se) { + err = NTFS_VOLUME_FUSE_ERROR; + goto err_out; + } + + ctx->mounted = TRUE; + +#if defined(linux) || defined(__uClinux__) + if (S_ISBLK(sbuf.st_mode) && (fstype == FSTYPE_FUSE)) + ntfs_log_info("%s", fuse26_kmod_msg); +#endif + setup_logging(parsed_options); + if (failed_secure) + ntfs_log_info("%s\n",failed_secure); + if (permissions_mode) + ntfs_log_info("%s, configuration type %d\n",permissions_mode, + 5 + POSIXACLS*6 - KERNELPERMS*3 + CACHEING); + + fuse_session_loop(se); + fuse_remove_signal_handlers(se); + + err = 0; + + fuse_unmount(opts.mnt_point, ctx->fc); + fuse_session_destroy(se); +err_out: + ntfs_mount_error(opts.device, opts.mnt_point, err); + if (ctx->abs_mnt_point) + free(ctx->abs_mnt_point); +err2: + ntfs_close(); + free(ctx); + free(parsed_options); + free(opts.options); + free(opts.device); + return err; +} + diff --git a/src/ntfs-3g.8.in b/src/ntfs-3g.8.in new file mode 100755 index 0000000..3134d21 --- a/dev/null +++ b/src/ntfs-3g.8.in @@ -0,0 +1,349 @@ +.\" Copyright (c) 2005-2006 Yura Pakhuchiy. +.\" Copyright (c) 2005 Richard Russon. +.\" Copyright (c) 2006-2009 Szabolcs Szakacsits. +.\" Copyright (c) 2009 Jean-Pierre Andre +.\" This file may be copied under the terms of the GNU Public License. +.\" +.TH NTFS-3G 8 "February 2010" "ntfs-3g @VERSION@" +.SH NAME +ntfs-3g \- Third Generation Read/Write NTFS Driver +.SH SYNOPSIS +.B ntfs-3g +\fB[-o \fIoption\fP\fB[,...]]\fR +.I volume mount_point +.br +.B mount \-t ntfs-3g +\fB[-o \fIoption\fP\fB[,...]]\fR +.I volume mount_point +.br +.B lowntfs-3g +\fB[-o \fIoption\fP\fB[,...]]\fR +.I volume mount_point +.br +.B mount \-t lowntfs-3g +\fB[-o \fIoption\fP\fB[,...]]\fR +.I volume mount_point +.SH DESCRIPTION +\fBntfs-3g\fR is an NTFS driver, which can create, remove, rename, move +files, directories, hard links, and streams; it can read and write files, +including streams, sparse files and transparently compressed files; it can +handle special files like symbolic links, devices, and FIFOs; moreover it +provides standard management of file ownership and permissions, including +POSIX ACLs. +.PP +It comes in two variants \fBntfs-3g\fR and \fBlowntfs-3g\fR with +a few differences mentioned below in relevant options descriptions. +.PP +The \fIvolume\fR to be mounted can be either a block device or +an image file. +.SS Access Handling and Security +By default, files and directories are owned by the effective +user and group of the mounting process and everybody has +full read, write, execution and directory browsing permissions. +You can also assign permissions to a single user by using the +.B uid +and/or the +.B gid +options together with the +.B umask, +or +.B fmask +and +.B dmask +options. +.PP +Doing so, Windows users have full access to the files created by +.B ntfs-3g. +.PP +But, by defining a Windows-to-Linux user mapping in the file +\fB.NTFS-3G/UserMapping\fP, you can benefit from the full ownership and +permissions features as defined by Posix and those ownership and +permissions will be applied to Windows users and conversely. +.PP +If +.B ntfs-3g +is set setuid-root then non-root users will +be also able to mount volumes. +.SS Windows Filename Compatibility +NTFS supports several filename namespaces: DOS, Win32 and POSIX. While the +\fBntfs-3g\fR driver handles all of them, it always creates new files in the +POSIX namespace for maximum portability and interoperability reasons. +This means that filenames are case sensitive and all characters are +allowed except '/' and '\\0'. This is perfectly legal on Windows, though +some application may get confused. If you find so then please report it +to the developer of the relevant Windows software. +.SS Alternate Data Streams (ADS) +NTFS stores all data in streams. Every file has exactly one unnamed +data stream and can have many named data streams. The size of a file is the +size of its unnamed data stream. By default, \fBntfs-3g\fR will only read +the unnamed data stream. +.PP +By using the options "streams_interface=windows", with the ntfs-3g driver +(not possible with lowntfs-3g), you will be able to read any named data +streams, simply by specifying the stream's name after a colon. +For example: +.RS +.sp +cat some.mp3:artist +.sp +.RE +Named data streams act like normal files, so you can read from them, write to +them and even delete them (using rm). You can list all the named data streams +a file has by getting the "ntfs.streams.list" extended attribute. +.SH OPTIONS +Below is a summary of the options that \fBntfs-3g\fR accepts. +.TP +\fBuid=\fP\fIvalue\fP and \fBgid=\fP\fIvalue\fP +Set the owner and the group of files and directories. The values are numerical. +The defaults are the uid and gid of the current process. +.TP +.BI umask= value +Set the bitmask of the file and directory permissions that are not +present. The value is given in octal. The default value is 0 which +means full access to everybody. +.TP +.BI fmask= value +Set the bitmask of the file permissions that are not present. +The value is given in octal. The default value is 0 which +means full access to everybody. +.TP +.BI dmask= value +Set the bitmask of the directory permissions that are not +present. The value is given in octal. The default value is 0 which +means full access to everybody. +.TP +.BI usermapping= file-name +Use file \fIfile-name\fP as the user mapping file instead of the default +\fB.NTFS-3G/UserMapping\fP. If \fIfile-name\fP defines a full path, the +file must be located on a partition previously mounted. If it defines a +relative path, it is interpreted relative to the root of NTFS partition +being mounted. +.P +.RS +When a user mapping file is defined, the options \fBuid=\fP, \fBgid=\fP, +\fBumask=\fP, \fBfmask=\fP, \fBdmask=\fP and \fBdsilent=\fP are ignored. +.RE +.TP +.B default_permissions +Use standard access control. This option requires either a user mapping +file to be present, or the options \fIuid=\fP and \fIgid=\fP of a user +to be defined. This option is set by default when a user mapping file +or an ownership related option is present. +.TP +.B inherit +When creating a new file, set its initial ownership and protections +according to inheritance rules defined in parent directory. These rules +deviate from Posix specifications, but yield a better Windows +compatibility. A valid user mapping file is required for this option +to be effective. +.TP +.B ro +Mount filesystem read\-only. Useful if Windows is hibernated or the +NTFS journal file is unclean. +.TP +.BI locale= value +This option can be useful when wanting a language specific locale environment. +It is however discouraged as it leads to files with untranslatable chars +to not be visible. Please see more information about this topic at +http://ntfs-3g.org/support.html#locale +.TP +.B force +Force the mounting even if the NTFS logfile is unclean. The logfile +will be unconditionally cleared. Use this option with caution and for +your own responsibility. +.TP +.B remove_hiberfile +Unlike in case of read-only mount, the read-write mount is denied if +the NTFS volume is hibernated. One needs either to resume Windows and +shutdown it properly, or use this option which will remove the Windows +hibernation file. Please note, this means that the saved Windows +session will be completely lost. Use this option for your own +responsibility. +.TP +.B atime, noatime, relatime +The +.B atime +option updates inode access time for each access. + +The +.B noatime +option disables inode access time updates which can speed up +file operations and prevent sleeping (notebook) disks spinning +up too often thus saving energy and disk lifetime. + +The +.B relatime +option is very similar to +.B noatime. +It updates inode access times relative to modify or change time. +The access time is only updated if the previous access time was earlier +than the current modify or change time. Unlike +.B noatime +this option doesn't break applications that need to know +if a file has been read since the last time it was modified. +This is the default behaviour. +.TP +.B show_sys_files +Show the system files in directory listings. +Otherwise the default behaviour is to hide the system files. +Please note that even when this option is specified, "$MFT" +may not be visible due to a glibc bug. +Furthermore, irrespectively of show_sys_files, all +files are accessible by name, for example you can always do +"ls \-l '$UpCase'". +.TP +.B allow_other +This option overrides the security measure restricting file access +to the user mounting the filesystem. This option is only +allowed to root, but this restriction can be overridden by +the 'user_allow_other' option in the /etc/fuse.conf file. +.TP +.BI max_read= value +With this option the maximum size of read operations can be set. +The default is infinite. Note that the size of read requests is +limited anyway to 32 pages (which is 128kbyte on i386). +.TP +.B silent +Do nothing on chmod and chown operations, but do not return error +when the user mapping file required by these operations is not defined. +This option is on by default. +.TP +.B no_def_opts +By default ntfs-3g acts as if "silent" were set, and +this option cancel this default behavior. +.TP +.BI streams_interface= value +This option controls how the user can access Alternate Data Streams (ADS) +or in other words, named data streams. It can be set +to, one of \fBnone\fR, \fBwindows\fR or \fBxattr\fR. If the option is set to +\fBnone\fR, the user will have no access to the named data streams. If it's set +to \fBwindows\fR, then the user can access them just like in Windows (eg. cat +file:stream). If it's set to \fBxattr\fR, then the named data streams are +mapped to xattrs and user can manipulate them using \fB{get,set}fattr\fR +utilities. The default is \fBxattr\fR. +.TP +.B user_xattr +Same as \fBstreams_interface=\fP\fIxattr\fP. +.TP +.B efs_raw +This option should only be used in backup or restore situation. +It changes the apparent size of files and the behavior of read and +write operation so that encrypted files can be saved and restored +without being decrypted. The \fBuser.ntfs.efsinfo\fP extended attribute +has also to be saved and restored for the file to be decrypted. +.TP +.B debug +Makes ntfs-3g to not detach from terminal and print a lot of debug output from +libntfs-3g and FUSE. +.TP +.B no_detach +Same as above but with less debug output. +.SH USER MAPPING +NTFS uses specific ids to record the ownership of files instead of +the \fBuid\fP and \fBgid\fP used by Linux. As a consequence a mapping +between the ids has to be defined for ownerships to be recorded into +NTFS and recognized. +.P +By default this mapping is fetched from the file \fB.NTFS-3G/UserMapping\fP +located in the NTFS partition. The option \fBusermapping=\fP may be used +to define another location. +.P +Each line in the user mapping file defines a mapping. It is organized +in three fields separated by colons. The first field identifies a \fBuid\fP, +the second field identifies a \fBgid\fP and the third one identifies the +corresponding NTFS id, known as a \fBSID\fP. The \fBuid\fP and the \fBgid\fP +are optional and defining both of them for the same \fBSID\fP is not +recommended. +.P +If no interoperation with Windows is needed, a single default mapping +with no uid and gid can be used. Just copy the example below and replace +the 9 and 10-digit numbers by any number not greater than 4294967295. +.RS +.sp +.B ::S-1-5-21-3141592653-589793238-462643383-10000 +.sp +.RE +If interoperation with Windows is needed, the mapping has to be defined +for each user and group known in both system, and the \fBSID\fPs used +by Windows has to be collected. This will lead to a user mapping file +like : +.RS +.sp +.B john::S-1-5-21-3141592653-589793238-462643383-1008 +.B mary::S-1-5-21-3141592653-589793238-462643383-1009 +.B :smith:S-1-5-21-3141592653-589793238-462643383-513 +.B ::S-1-5-21-3141592653-589793238-462643383-10000 +.sp +.RE +.P +The utility \fBntfs-3g.usermap\fP may be used to create the user mapping file. +.SH EXAMPLES +Mount /dev/sda1 to /mnt/windows: +.RS +.sp +.B ntfs-3g /dev/sda1 /mnt/windows +.sp +.RE +or +.RS +.sp +.B mount -t ntfs-3g /dev/sda1 /mnt/windows +.sp +.RE +Read\-only mount /dev/sda5 to /home/user/mnt and make user with uid 1000 +to be the owner of all files: +.RS +.sp +.B ntfs-3g /dev/sda5 /home/user/mnt \-o ro,uid=1000 +.sp +.RE +/etc/fstab entry for the above: +.RS +.sp +.B /dev/sda5 /home/user/mnt ntfs\-3g ro,uid=1000 0 0 +.sp +.RE +Unmount /mnt/windows: +.RS +.sp +.B umount /mnt/windows +.sp +.RE +.SH EXIT CODES +To facilitate the use of the +.B ntfs-3g +driver in scripts, an exit code is returned to give an indication of the +mountability status of a volume. Value 0 means success, and all other +ones mean an error. The unique error codes are documented in the +.BR ntfs-3g.probe (8) +manual page. +.SH KNOWN ISSUES +Please see +.RS +.sp +http://www.tuxera.com/support/ +.sp +.RE +for common questions and known issues. +If you would find a new one in the latest release of +the software then please send an email describing it +in detail. You can contact the +development team on the ntfs\-3g\-devel@lists.sf.net +address. +.SH AUTHORS +.B ntfs-3g +was based on and a major improvement to ntfsmount and libntfs which were +written by Yura Pakhuchiy and the Linux-NTFS team. The improvements were +made, the ntfs-3g project was initiated and currently led by long time +Linux-NTFS team developer Szabolcs Szakacsits (szaka@tuxera.com). +.SH THANKS +Several people made heroic efforts, often over five or more +years which resulted the ntfs-3g driver. Most importantly they are +Anton Altaparmakov, Jean-Pierre André, Richard Russon, Szabolcs Szakacsits, +Yura Pakhuchiy, Yuval Fledel, and the author of the groundbreaking FUSE +filesystem development framework, Miklos Szeredi. +.SH SEE ALSO +.BR ntfs-3g.probe (8), +.BR ntfsprogs (8), +.BR attr (5), +.BR getfattr (1) diff --git a/src/ntfs-3g.c b/src/ntfs-3g.c new file mode 100755 index 0000000..73a66b9 --- a/dev/null +++ b/src/ntfs-3g.c @@ -0,0 +1,4461 @@ +/** + * ntfs-3g - Third Generation NTFS Driver + * + * Copyright (c) 2005-2007 Yura Pakhuchiy + * Copyright (c) 2005 Yuval Fledel + * Copyright (c) 2006-2009 Szabolcs Szakacsits + * Copyright (c) 2007-2010 Jean-Pierre Andre + * Copyright (c) 2009 Erik Larsson + * + * This file is originated from the Linux-NTFS project. + * + * 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 (in the main directory of the NTFS-3G + * distribution in the file COPYING); if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "config.h" + +#include + +#if !defined(FUSE_VERSION) || (FUSE_VERSION < 26) +#error "***********************************************************" +#error "* *" +#error "* Compilation requires at least FUSE version 2.6.0! *" +#error "* *" +#error "***********************************************************" +#endif + +#ifdef FUSE_INTERNAL +#define FUSE_TYPE "integrated FUSE" +#else +#define FUSE_TYPE "external FUSE" +#endif + +#ifdef HAVE_STDIO_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_ERRNO_H +#include +#endif +#ifdef HAVE_FCNTL_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_LOCALE_H +#include +#endif +#include +#ifdef HAVE_LIMITS_H +#include +#endif +#include +#include +#include + +#ifdef HAVE_SETXATTR +#include +#endif + +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_MKDEV_H +#include +#endif + +#if defined(__APPLE__) || defined(__DARWIN__) +#include +#endif /* defined(__APPLE__) || defined(__DARWIN__) */ + +#include "compat.h" +#include "attrib.h" +#include "inode.h" +#include "volume.h" +#include "dir.h" +#include "unistr.h" +#include "layout.h" +#include "index.h" +#include "ntfstime.h" +#include "security.h" +#include "reparse.h" +#include "object_id.h" +#include "efs.h" +#include "logging.h" +#include "misc.h" + +/* + * The following permission checking modes are governed by + * the HPERMSCONFIG value in param.h + */ + +/* ACLS may be checked by kernel (requires a fuse patch) or here */ +#define KERNELACLS ((HPERMSCONFIG > 6) & (HPERMSCONFIG < 10)) +/* basic permissions may be checked by kernel or here */ +#define KERNELPERMS (((HPERMSCONFIG - 1) % 6) < 3) +/* may want to use fuse/kernel cacheing */ +#define CACHEING (!(HPERMSCONFIG % 3)) + +#if KERNELACLS & !KERNELPERMS +#error Incompatible options KERNELACLS and KERNELPERMS +#endif + + /* sometimes the kernel cannot check access */ +#define ntfs_real_allowed_access(scx, ni, type) ntfs_allowed_access(scx, ni, type) +#if POSIXACLS & KERNELPERMS & !KERNELACLS + /* short-circuit if PERMS checked by kernel and ACLs by fs */ +#define ntfs_allowed_access(scx, ni, type) \ + ((scx)->vol->secure_flags & (1 << SECURITY_DEFAULT) \ + ? 1 : ntfs_allowed_access(scx, ni, type)) +#endif + +#define set_archive(ni) (ni)->flags |= FILE_ATTR_ARCHIVE + +typedef enum { + FSTYPE_NONE, + FSTYPE_UNKNOWN, + FSTYPE_FUSE, + FSTYPE_FUSEBLK +} fuse_fstype; + +typedef enum { + ATIME_ENABLED, + ATIME_DISABLED, + ATIME_RELATIVE +} ntfs_atime_t; + +typedef struct { + fuse_fill_dir_t filler; + void *buf; +} ntfs_fuse_fill_context_t; + +typedef enum { + NF_STREAMS_INTERFACE_NONE, /* No access to named data streams. */ + NF_STREAMS_INTERFACE_XATTR, /* Map named data streams to xattrs. */ + NF_STREAMS_INTERFACE_OPENXATTR, /* Same, not limited to "user." */ + NF_STREAMS_INTERFACE_WINDOWS, /* "file:stream" interface. */ +} ntfs_fuse_streams_interface; + +enum { + CLOSE_COMPRESSED = 1, + CLOSE_ENCRYPTED = 2 +}; + +typedef struct { + ntfs_volume *vol; + unsigned int uid; + unsigned int gid; + unsigned int fmask; + unsigned int dmask; + ntfs_fuse_streams_interface streams; + ntfs_atime_t atime; + BOOL ro; + BOOL show_sys_files; + BOOL silent; + BOOL recover; + BOOL hiberfile; + BOOL debug; + BOOL no_detach; + BOOL blkdev; + BOOL mounted; +#ifdef HAVE_SETXATTR /* extended attributes interface required */ + BOOL efs_raw; +#endif /* HAVE_SETXATTR */ + struct fuse_chan *fc; + BOOL inherit; + unsigned int secure_flags; + char *usermap_path; + char *abs_mnt_point; + struct PERMISSIONS_CACHE *seccache; + struct SECURITY_CONTEXT security; +} ntfs_fuse_context_t; + +static struct options { + char *mnt_point; /* Mount point */ + char *options; /* Mount options */ + char *device; /* Device to mount */ +} opts; + +static const char *EXEC_NAME = "ntfs-3g"; +static char def_opts[] = "silent,allow_other,nonempty,"; +static ntfs_fuse_context_t *ctx; +static u32 ntfs_sequence; + +static const char *usage_msg = +"\n" +"%s %s %s %d - Third Generation NTFS Driver\n" +"\t\tConfiguration type %d, " +#ifdef HAVE_SETXATTR +"XATTRS are on, " +#else +"XATTRS are off, " +#endif +#if POSIXACLS +"POSIX ACLS are on\n" +#else +"POSIX ACLS are off\n" +#endif +"\n" +"Copyright (C) 2005-2007 Yura Pakhuchiy\n" +"Copyright (C) 2006-2009 Szabolcs Szakacsits\n" +"Copyright (C) 2007-2010 Jean-Pierre Andre\n" +"Copyright (C) 2009 Erik Larsson\n" +"\n" +"Usage: %s [-o option[,...]] \n" +"\n" +"Options: ro (read-only mount), remove_hiberfile, uid=, gid=,\n" +" umask=, fmask=, dmask=, streams_interface=.\n" +" Please see the details in the manual (type: man ntfs-3g).\n" +"\n" +"Example: ntfs-3g /dev/sda1 /mnt/windows\n" +"\n" +"%s"; + +static const char ntfs_bad_reparse[] = "unsupported reparse point"; + +#ifdef FUSE_INTERNAL +int drop_privs(void); +int restore_privs(void); +#else +/* + * setuid and setgid root ntfs-3g denies to start with external FUSE, + * therefore the below functions are no-op in such case. + */ +static int drop_privs(void) { return 0; } +#if defined(linux) || defined(__uClinux__) +static int restore_privs(void) { return 0; } +#endif + +static const char *setuid_msg = +"Mount is denied because setuid and setgid root ntfs-3g is insecure with the\n" +"external FUSE library. Either remove the setuid/setgid bit from the binary\n" +"or rebuild NTFS-3G with integrated FUSE support and make it setuid root.\n" +"Please see more information at http://ntfs-3g.org/support.html#unprivileged\n"; + +static const char *unpriv_fuseblk_msg = +"Unprivileged user can not mount NTFS block devices using the external FUSE\n" +"library. Either mount the volume as root, or rebuild NTFS-3G with integrated\n" +"FUSE support and make it setuid root. Please see more information at\n" +"http://ntfs-3g.org/support.html#unprivileged\n"; +#endif + + +/** + * ntfs_fuse_is_named_data_stream - check path to be to named data stream + * @path: path to check + * + * Returns 1 if path is to named data stream or 0 otherwise. + */ +static int ntfs_fuse_is_named_data_stream(const char *path) +{ + if (strchr(path, ':') && ctx->streams == NF_STREAMS_INTERFACE_WINDOWS) + return 1; + return 0; +} + +static void ntfs_fuse_update_times(ntfs_inode *ni, ntfs_time_update_flags mask) +{ + if (ctx->atime == ATIME_DISABLED) + mask &= ~NTFS_UPDATE_ATIME; + else if (ctx->atime == ATIME_RELATIVE && mask == NTFS_UPDATE_ATIME && + (le64_to_cpu(ni->last_access_time) + >= le64_to_cpu(ni->last_data_change_time)) && + (le64_to_cpu(ni->last_access_time) + >= le64_to_cpu(ni->last_mft_change_time))) + return; + ntfs_inode_update_times(ni, mask); +} + +static s64 ntfs_get_nr_free_mft_records(ntfs_volume *vol) +{ + ntfs_attr *na = vol->mftbmp_na; + s64 nr_free = ntfs_attr_get_free_bits(na); + + if (nr_free >= 0) + nr_free += (na->allocated_size - na->data_size) << 3; + return nr_free; +} + +/* + * Fill a security context as needed by security functions + * returns TRUE if there is a user mapping, + * FALSE if there is none + * This is not an error and the context is filled anyway, + * it is used for implicit Windows-like inheritance + */ + +static BOOL ntfs_fuse_fill_security_context(struct SECURITY_CONTEXT *scx) +{ + struct fuse_context *fusecontext; + + scx->vol = ctx->vol; + scx->mapping[MAPUSERS] = ctx->security.mapping[MAPUSERS]; + scx->mapping[MAPGROUPS] = ctx->security.mapping[MAPGROUPS]; + scx->pseccache = &ctx->seccache; + fusecontext = fuse_get_context(); + scx->uid = fusecontext->uid; + scx->gid = fusecontext->gid; + scx->tid = fusecontext->pid; +#ifdef FUSE_CAP_DONT_MASK + /* the umask can be processed by the file system */ + scx->umask = fusecontext->umask; +#else + /* the umask if forced by fuse on creation */ + scx->umask = 0; +#endif + + return (ctx->security.mapping[MAPUSERS] != (struct MAPPING*)NULL); +} + +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + +/* + * Check access to parent directory + * + * directory and file inodes are only opened when not fed in, + * they *HAVE TO* be fed in when already open, however + * file inode is only useful when S_ISVTX is requested + * + * returns 1 if allowed, + * 0 if not allowed or some error occurred (errno tells why) + */ + +static int ntfs_allowed_dir_access(struct SECURITY_CONTEXT *scx, + const char *path, ntfs_inode *dir_ni, + ntfs_inode *ni, mode_t accesstype) +{ + int allowed; + ntfs_inode *ni2; + ntfs_inode *dir_ni2; + char *dirpath; + char *name; + struct stat stbuf; + +#if POSIXACLS & KERNELPERMS & !KERNELACLS + /* short-circuit if PERMS checked by kernel and ACLs by fs */ + if (scx->vol->secure_flags & (1 << SECURITY_DEFAULT)) + allowed = 1; + else +#endif + if (dir_ni) + allowed = ntfs_real_allowed_access(scx, dir_ni, + accesstype); + else { + allowed = 0; + dirpath = strdup(path); + if (dirpath) { + /* the root of file system is seen as a parent of itself */ + /* is that correct ? */ + name = strrchr(dirpath, '/'); + *name = 0; + dir_ni2 = ntfs_pathname_to_inode(scx->vol, + NULL, dirpath); + if (dir_ni2) { + allowed = ntfs_real_allowed_access(scx, + dir_ni2, accesstype); + if (ntfs_inode_close(dir_ni2)) + allowed = 0; + } + free(dirpath); + } + } + /* + * for a not-owned sticky directory, have to + * check whether file itself is owned + */ + if ((accesstype == (S_IWRITE + S_IEXEC + S_ISVTX)) + && (allowed == 2)) { + if (ni) + ni2 = ni; + else + ni2 = ntfs_pathname_to_inode(scx->vol, NULL, + path); + allowed = 0; + if (ni2) { + allowed = (ntfs_get_owner_mode(scx,ni2,&stbuf) + >= 0) + && (stbuf.st_uid == scx->uid); + if (!ni) + ntfs_inode_close(ni2); + } + } + return (allowed); +} + +#endif + +#ifdef HAVE_SETXATTR /* extended attributes interface required */ + +/* + * Check access to parent directory + * + * for non-standard cases where access control cannot be checked by kernel + * + * no known situations where S_ISVTX is requested + * + * returns 1 if allowed, + * 0 if not allowed or some error occurred (errno tells why) + */ + +static int ntfs_allowed_real_dir_access(struct SECURITY_CONTEXT *scx, + const char *path, ntfs_inode *dir_ni, + mode_t accesstype) +{ + int allowed; + ntfs_inode *dir_ni2; + char *dirpath; + char *name; + + if (dir_ni) + allowed = ntfs_real_allowed_access(scx, dir_ni, accesstype); + else { + allowed = 0; + dirpath = strdup(path); + if (dirpath) { + /* the root of file system is seen as a parent of itself */ + /* is that correct ? */ + name = strrchr(dirpath, '/'); + *name = 0; + dir_ni2 = ntfs_pathname_to_inode(scx->vol, NULL, + dirpath); + if (dir_ni2) { + allowed = ntfs_real_allowed_access(scx, + dir_ni2, accesstype); + if (ntfs_inode_close(dir_ni2)) + allowed = 0; + } + free(dirpath); + } + } + return (allowed); +} + +#endif /* HAVE_SETXATTR */ + +/** + * ntfs_fuse_statfs - return information about mounted NTFS volume + * @path: ignored (but fuse requires it) + * @sfs: statfs structure in which to return the information + * + * Return information about the mounted NTFS volume @sb in the statfs structure + * pointed to by @sfs (this is initialized with zeros before ntfs_statfs is + * called). We interpret the values to be correct of the moment in time at + * which we are called. Most values are variable otherwise and this isn't just + * the free values but the totals as well. For example we can increase the + * total number of file nodes if we run out and we can keep doing this until + * there is no more space on the volume left at all. + * + * This code based on ntfs_statfs from ntfs kernel driver. + * + * Returns 0 on success or -errno on error. + */ +#if HAVE_SYS_STATVFS_H +static int ntfs_fuse_statfs(const char *path __attribute__((unused)), + struct statvfs *sfs) +{ + s64 size; + int delta_bits; + ntfs_volume *vol; + + vol = ctx->vol; + if (!vol) + return -ENODEV; + + /* + * File system block size. Used to calculate used/free space by df. + * Incorrectly documented as "optimal transfer block size". + */ + sfs->f_bsize = vol->cluster_size; + + /* Fundamental file system block size, used as the unit. */ + sfs->f_frsize = vol->cluster_size; + + /* + * Total number of blocks on file system in units of f_frsize. + * Since inodes are also stored in blocks ($MFT is a file) hence + * this is the number of clusters on the volume. + */ + sfs->f_blocks = vol->nr_clusters; + + /* Free blocks available for all and for non-privileged processes. */ + size = vol->free_clusters; + if (size < 0) + size = 0; + sfs->f_bavail = sfs->f_bfree = size; + + /* Free inodes on the free space */ + delta_bits = vol->cluster_size_bits - vol->mft_record_size_bits; + if (delta_bits >= 0) + size <<= delta_bits; + else + size >>= -delta_bits; + + /* Number of inodes at this point in time. */ + sfs->f_files = (vol->mftbmp_na->allocated_size << 3) + size; + + /* Free inodes available for all and for non-privileged processes. */ + size += vol->free_mft_records; + if (size < 0) + size = 0; + sfs->f_ffree = sfs->f_favail = size; + + /* Maximum length of filenames. */ + sfs->f_namemax = NTFS_MAX_NAME_LEN; + return 0; +} +#endif + + +/** + * ntfs_fuse_parse_path - split path to path and stream name. + * @org_path: path to split + * @path: pointer to buffer in which parsed path saved + * @stream_name: pointer to buffer where stream name in unicode saved + * + * This function allocates buffers for @*path and @*stream, user must free them + * after use. + * + * Return values: + * <0 Error occurred, return -errno; + * 0 No stream name, @*stream is not allocated and set to AT_UNNAMED. + * >0 Stream name length in unicode characters. + */ +static int ntfs_fuse_parse_path(const char *org_path, char **path, + ntfschar **stream_name) +{ + char *stream_name_mbs; + int res; + + stream_name_mbs = strdup(org_path); + if (!stream_name_mbs) + return -errno; + if (ctx->streams == NF_STREAMS_INTERFACE_WINDOWS) { + *path = strsep(&stream_name_mbs, ":"); + if (stream_name_mbs) { + *stream_name = NULL; + res = ntfs_mbstoucs(stream_name_mbs, stream_name); + if (res < 0) + return -errno; + return res; + } + } else + *path = stream_name_mbs; + *stream_name = AT_UNNAMED; + return 0; +} + +static void set_fuse_error(int *err) +{ + if (!*err) + *err = -errno; +} + +#if defined(__APPLE__) || defined(__DARWIN__) +static int ntfs_macfuse_getxtimes(const char *org_path, + struct timespec *bkuptime, struct timespec *crtime) +{ + int res = 0; + ntfs_inode *ni; + char *path = NULL; + ntfschar *stream_name; + int stream_name_len; + + stream_name_len = ntfs_fuse_parse_path(org_path, &path, &stream_name); + if (stream_name_len < 0) + return stream_name_len; + memset(bkuptime, 0, sizeof(struct timespec)); + memset(crtime, 0, sizeof(struct timespec)); + ni = ntfs_pathname_to_inode(ctx->vol, NULL, path); + if (!ni) { + res = -errno; + goto exit; + } + + /* We have no backup timestamp in NTFS. */ + crtime->tv_sec = ni->creation_time; +exit: + if (ntfs_inode_close(ni)) + set_fuse_error(&res); + free(path); + if (stream_name_len) + free(stream_name); + return res; +} + +int ntfs_macfuse_setcrtime(const char *path, const struct timespec *tv) +{ + ntfs_inode *ni; + int res = 0; + + if (ntfs_fuse_is_named_data_stream(path)) + return -EINVAL; /* n/a for named data streams. */ + ni = ntfs_pathname_to_inode(ctx->vol, NULL, path); + if (!ni) + return -errno; + + if (tv) { + ni->creation_time = tv->tv_sec; + ntfs_fuse_update_times(ni, NTFS_UPDATE_CTIME); + } + + if (ntfs_inode_close(ni)) + set_fuse_error(&res); + return res; +} + +int ntfs_macfuse_setbkuptime(const char *path, const struct timespec *tv) +{ + ntfs_inode *ni; + int res = 0; + + if (ntfs_fuse_is_named_data_stream(path)) + return -EINVAL; /* n/a for named data streams. */ + ni = ntfs_pathname_to_inode(ctx->vol, NULL, path); + if (!ni) + return -errno; + + /* + * Only pretending to set backup time successfully to please the APIs of + * Mac OS X. In reality, NTFS has no backup time. + */ + + if (ntfs_inode_close(ni)) + set_fuse_error(&res); + return res; +} + +int ntfs_macfuse_setchgtime(const char *path, const struct timespec *tv) +{ + ntfs_inode *ni; + int res = 0; + + if (ntfs_fuse_is_named_data_stream(path)) + return -EINVAL; /* n/a for named data streams. */ + ni = ntfs_pathname_to_inode(ctx->vol, NULL, path); + if (!ni) + return -errno; + + if (tv) { + ni->last_mft_change_time = tv->tv_sec; + ntfs_fuse_update_times(ni, 0); + } + + if (ntfs_inode_close(ni)) + set_fuse_error(&res); + return res; +} +#endif /* defined(__APPLE__) || defined(__DARWIN__) */ + +#if defined(FUSE_CAP_DONT_MASK) || (defined(__APPLE__) || defined(__DARWIN__)) +static void *ntfs_init(struct fuse_conn_info *conn) +{ +#if defined(__APPLE__) || defined(__DARWIN__) + FUSE_ENABLE_XTIMES(conn); +#endif +#ifdef FUSE_CAP_DONT_MASK + /* request umask not to be enforced by fuse */ + conn->want |= FUSE_CAP_DONT_MASK; +#endif /* defined FUSE_CAP_DONT_MASK */ + return NULL; +} +#endif /* defined(FUSE_CAP_DONT_MASK) || (defined(__APPLE__) || defined(__DARWIN__)) */ + +static int ntfs_fuse_getattr(const char *org_path, struct stat *stbuf) +{ + int res = 0; + ntfs_inode *ni; + ntfs_attr *na; + char *path = NULL; + ntfschar *stream_name; + int stream_name_len; + BOOL withusermapping; + struct SECURITY_CONTEXT security; + + stream_name_len = ntfs_fuse_parse_path(org_path, &path, &stream_name); + if (stream_name_len < 0) + return stream_name_len; + memset(stbuf, 0, sizeof(struct stat)); + ni = ntfs_pathname_to_inode(ctx->vol, NULL, path); + if (!ni) { + res = -errno; + goto exit; + } + withusermapping = ntfs_fuse_fill_security_context(&security); +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + /* + * make sure the parent directory is searchable + */ + if (withusermapping + && !ntfs_allowed_dir_access(&security,path, + (!strcmp(org_path,"/") ? ni : (ntfs_inode*)NULL), + ni, S_IEXEC)) { + res = -EACCES; + goto exit; + } +#endif + if (((ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) + || (ni->flags & FILE_ATTR_REPARSE_POINT)) + && !stream_name_len) { + if (ni->flags & FILE_ATTR_REPARSE_POINT) { + char *target; + int attr_size; + + errno = 0; + target = ntfs_make_symlink(ni, ctx->abs_mnt_point, &attr_size); + /* + * If the reparse point is not a valid + * directory junction, and there is no error + * we still display as a symlink + */ + if (target || (errno == EOPNOTSUPP)) { + /* returning attribute size */ + if (target) + stbuf->st_size = attr_size; + else + stbuf->st_size = sizeof(ntfs_bad_reparse); + stbuf->st_blocks = (ni->allocated_size + 511) >> 9; + stbuf->st_nlink = le16_to_cpu(ni->mrec->link_count); + stbuf->st_mode = S_IFLNK; + free(target); + } else { + res = -errno; + goto exit; + } + } else { + /* Directory. */ + stbuf->st_mode = S_IFDIR | (0777 & ~ctx->dmask); + /* get index size, if not known */ + if (!test_nino_flag(ni, KnownSize)) { + na = ntfs_attr_open(ni, AT_INDEX_ALLOCATION, NTFS_INDEX_I30, 4); + if (na) { + ni->data_size = na->data_size; + ni->allocated_size = na->allocated_size; + set_nino_flag(ni, KnownSize); + ntfs_attr_close(na); + } + } + stbuf->st_size = ni->data_size; + stbuf->st_blocks = ni->allocated_size >> 9; + stbuf->st_nlink = 1; /* Make find(1) work */ + } + } else { + /* Regular or Interix (INTX) file. */ + stbuf->st_mode = S_IFREG; + stbuf->st_size = ni->data_size; +#ifdef HAVE_SETXATTR /* extended attributes interface required */ + /* + * return data size rounded to next 512 byte boundary for + * encrypted files to include padding required for decryption + * also include 2 bytes for padding info + */ + if (ctx->efs_raw && ni->flags & FILE_ATTR_ENCRYPTED) + stbuf->st_size = ((ni->data_size + 511) & ~511) + 2; +#endif /* HAVE_SETXATTR */ + /* + * Temporary fix to make ActiveSync work via Samba 3.0. + * See more on the ntfs-3g-devel list. + */ + stbuf->st_blocks = (ni->allocated_size + 511) >> 9; + stbuf->st_nlink = le16_to_cpu(ni->mrec->link_count); + if (ni->flags & FILE_ATTR_SYSTEM || stream_name_len) { + na = ntfs_attr_open(ni, AT_DATA, stream_name, + stream_name_len); + if (!na) { + if (stream_name_len) + res = -ENOENT; + goto exit; + } + if (stream_name_len) { + stbuf->st_size = na->data_size; + stbuf->st_blocks = na->allocated_size >> 9; + } + /* Check whether it's Interix FIFO or socket. */ + if (!(ni->flags & FILE_ATTR_HIDDEN) && + !stream_name_len) { + /* FIFO. */ + if (na->data_size == 0) + stbuf->st_mode = S_IFIFO; + /* Socket link. */ + if (na->data_size == 1) + stbuf->st_mode = S_IFSOCK; + } +#ifdef HAVE_SETXATTR /* extended attributes interface required */ + /* encrypted named stream */ + /* round size up to next 512 byte boundary */ + if (ctx->efs_raw && stream_name_len && + (na->data_flags & ATTR_IS_ENCRYPTED) && + NAttrNonResident(na)) + stbuf->st_size = ((na->data_size+511) & ~511)+2; +#endif /* HAVE_SETXATTR */ + /* + * Check whether it's Interix symbolic link, block or + * character device. + */ + if ((size_t)na->data_size <= sizeof(INTX_FILE_TYPES) + + sizeof(ntfschar) * PATH_MAX + && (size_t)na->data_size > + sizeof(INTX_FILE_TYPES) + && !stream_name_len) { + + INTX_FILE *intx_file; + + intx_file = ntfs_malloc(na->data_size); + if (!intx_file) { + res = -errno; + ntfs_attr_close(na); + goto exit; + } + if (ntfs_attr_pread(na, 0, na->data_size, + intx_file) != na->data_size) { + res = -errno; + free(intx_file); + ntfs_attr_close(na); + goto exit; + } + if (intx_file->magic == INTX_BLOCK_DEVICE && + na->data_size == offsetof( + INTX_FILE, device_end)) { + stbuf->st_mode = S_IFBLK; + stbuf->st_rdev = makedev(le64_to_cpu( + intx_file->major), + le64_to_cpu( + intx_file->minor)); + } + if (intx_file->magic == INTX_CHARACTER_DEVICE && + na->data_size == offsetof( + INTX_FILE, device_end)) { + stbuf->st_mode = S_IFCHR; + stbuf->st_rdev = makedev(le64_to_cpu( + intx_file->major), + le64_to_cpu( + intx_file->minor)); + } + if (intx_file->magic == INTX_SYMBOLIC_LINK) + stbuf->st_mode = S_IFLNK; + free(intx_file); + } + ntfs_attr_close(na); + } + stbuf->st_mode |= (0777 & ~ctx->fmask); + } + if (withusermapping) { + if (ntfs_get_owner_mode(&security,ni,stbuf) < 0) + set_fuse_error(&res); + } else { + stbuf->st_uid = ctx->uid; + stbuf->st_gid = ctx->gid; + } + if (S_ISLNK(stbuf->st_mode)) + stbuf->st_mode |= 0777; + stbuf->st_ino = ni->mft_no; +#ifdef HAVE_STRUCT_STAT_ST_ATIMESPEC + stbuf->st_atimespec = ntfs2timespec(ni->last_access_time); + stbuf->st_ctimespec = ntfs2timespec(ni->last_mft_change_time); + stbuf->st_mtimespec = ntfs2timespec(ni->last_data_change_time); +#elif defined(HAVE_STRUCT_STAT_ST_ATIM) + stbuf->st_atim = ntfs2timespec(ni->last_access_time); + stbuf->st_ctim = ntfs2timespec(ni->last_mft_change_time); + stbuf->st_mtim = ntfs2timespec(ni->last_data_change_time); +#elif defined(HAVE_STRUCT_STAT_ST_ATIMENSEC) + { + struct timespec ts; + + ts = ntfs2timespec(ni->last_access_time); + stbuf->st_atime = ts.tv_sec; + stbuf->st_atimensec = ts.tv_nsec; + ts = ntfs2timespec(ni->last_mft_change_time); + stbuf->st_ctime = ts.tv_sec; + stbuf->st_ctimensec = ts.tv_nsec; + ts = ntfs2timespec(ni->last_data_change_time); + stbuf->st_mtime = ts.tv_sec; + stbuf->st_mtimensec = ts.tv_nsec; + } +#else +#warning "No known way to set nanoseconds in struct stat !" + { + struct timespec ts; + + ts = ntfs2timespec(ni->last_access_time); + stbuf->st_atime = ts.tv_sec; + ts = ntfs2timespec(ni->last_mft_change_time); + stbuf->st_ctime = ts.tv_sec; + ts = ntfs2timespec(ni->last_data_change_time); + stbuf->st_mtime = ts.tv_sec; + } +#endif +exit: + if (ntfs_inode_close(ni)) + set_fuse_error(&res); + free(path); + if (stream_name_len) + free(stream_name); + return res; +} + +static int ntfs_fuse_readlink(const char *org_path, char *buf, size_t buf_size) +{ + char *path; + ntfschar *stream_name; + ntfs_inode *ni = NULL; + ntfs_attr *na = NULL; + INTX_FILE *intx_file = NULL; + int stream_name_len, res = 0; + + /* Get inode. */ + stream_name_len = ntfs_fuse_parse_path(org_path, &path, &stream_name); + if (stream_name_len < 0) + return stream_name_len; + if (stream_name_len > 0) { + res = -EINVAL; + goto exit; + } + ni = ntfs_pathname_to_inode(ctx->vol, NULL, path); + if (!ni) { + res = -errno; + goto exit; + } + /* + * Reparse point : analyze as a junction point + */ + if (ni->flags & FILE_ATTR_REPARSE_POINT) { + char *target; + int attr_size; + + errno = 0; + res = 0; + target = ntfs_make_symlink(ni, ctx->abs_mnt_point, &attr_size); + if (target) { + strncpy(buf,target,buf_size); + free(target); + } else + if (errno == EOPNOTSUPP) + strcpy(buf,ntfs_bad_reparse); + else + res = -errno; + goto exit; + } + /* Sanity checks. */ + if (!(ni->flags & FILE_ATTR_SYSTEM)) { + res = -EINVAL; + goto exit; + } + na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0); + if (!na) { + res = -errno; + goto exit; + } + if ((size_t)na->data_size <= sizeof(INTX_FILE_TYPES)) { + res = -EINVAL; + goto exit; + } + if ((size_t)na->data_size > sizeof(INTX_FILE_TYPES) + + sizeof(ntfschar) * PATH_MAX) { + res = -ENAMETOOLONG; + goto exit; + } + /* Receive file content. */ + intx_file = ntfs_malloc(na->data_size); + if (!intx_file) { + res = -errno; + goto exit; + } + if (ntfs_attr_pread(na, 0, na->data_size, intx_file) != na->data_size) { + res = -errno; + goto exit; + } + /* Sanity check. */ + if (intx_file->magic != INTX_SYMBOLIC_LINK) { + res = -EINVAL; + goto exit; + } + /* Convert link from unicode to local encoding. */ + if (ntfs_ucstombs(intx_file->target, (na->data_size - + offsetof(INTX_FILE, target)) / sizeof(ntfschar), + &buf, buf_size) < 0) { + res = -errno; + goto exit; + } +exit: + if (intx_file) + free(intx_file); + if (na) + ntfs_attr_close(na); + if (ntfs_inode_close(ni)) + set_fuse_error(&res); + free(path); + if (stream_name_len) + free(stream_name); + return res; +} + +static int ntfs_fuse_filler(ntfs_fuse_fill_context_t *fill_ctx, + const ntfschar *name, const int name_len, const int name_type, + const s64 pos __attribute__((unused)), const MFT_REF mref, + const unsigned dt_type __attribute__((unused))) +{ + char *filename = NULL; + int ret = 0; + int filenamelen = -1; + + if (name_type == FILE_NAME_DOS) + return 0; + + if ((filenamelen = ntfs_ucstombs(name, name_len, &filename, 0)) < 0) { + ntfs_log_perror("Filename decoding failed (inode %llu)", + (unsigned long long)MREF(mref)); + return -1; + } + + if (ntfs_fuse_is_named_data_stream(filename)) { + ntfs_log_error("Unable to access '%s' (inode %llu) with " + "current named streams access interface.\n", + filename, (unsigned long long)MREF(mref)); + free(filename); + return 0; + } + + if (MREF(mref) == FILE_root || MREF(mref) >= FILE_first_user || + ctx->show_sys_files) { + struct stat st = { .st_ino = MREF(mref) }; + + if (dt_type == NTFS_DT_REG) + st.st_mode = S_IFREG | (0777 & ~ctx->fmask); + else if (dt_type == NTFS_DT_DIR) + st.st_mode = S_IFDIR | (0777 & ~ctx->dmask); + +#if defined(__APPLE__) || defined(__DARWIN__) + /* + * Returning file names larger than MAXNAMLEN (255) bytes + * causes Darwin/Mac OS X to bug out and skip the entry. + */ + if (filenamelen > MAXNAMLEN) { + ntfs_log_debug("Truncating %d byte filename to " + "%d bytes.\n", filenamelen, MAXNAMLEN); + ntfs_log_debug(" before: '%s'\n", filename); + memset(filename + MAXNAMLEN, 0, filenamelen - MAXNAMLEN); + ntfs_log_debug(" after: '%s'\n", filename); + } +#endif /* defined(__APPLE__) || defined(__DARWIN__) */ + + ret = fill_ctx->filler(fill_ctx->buf, filename, &st, 0); + } + + free(filename); + return ret; +} + +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + +static int ntfs_fuse_opendir(const char *path, + struct fuse_file_info *fi) +{ + int res = 0; + ntfs_inode *ni; + int accesstype; + struct SECURITY_CONTEXT security; + + if (ntfs_fuse_is_named_data_stream(path)) + return -EINVAL; /* n/a for named data streams. */ + + ni = ntfs_pathname_to_inode(ctx->vol, NULL, path); + if (ni) { + if (ntfs_fuse_fill_security_context(&security)) { + if (fi->flags & O_WRONLY) + accesstype = S_IWRITE; + else + if (fi->flags & O_RDWR) + accesstype = S_IWRITE | S_IREAD; + else + accesstype = S_IREAD; + /* + * directory must be searchable + * and requested access be allowed + */ + if (!strcmp(path,"/") + ? !ntfs_allowed_dir_access(&security, + path, ni, ni, accesstype | S_IEXEC) + : !ntfs_allowed_dir_access(&security, path, + (ntfs_inode*)NULL, ni, S_IEXEC) + || !ntfs_allowed_access(&security, + ni,accesstype)) + res = -EACCES; + } + if (ntfs_inode_close(ni)) + set_fuse_error(&res); + } else + res = -errno; + return res; +} + +#endif + +static int ntfs_fuse_readdir(const char *path, void *buf, + fuse_fill_dir_t filler, off_t offset __attribute__((unused)), + struct fuse_file_info *fi __attribute__((unused))) +{ + ntfs_fuse_fill_context_t fill_ctx; + ntfs_inode *ni; + s64 pos = 0; + int err = 0; + + fill_ctx.filler = filler; + fill_ctx.buf = buf; + ni = ntfs_pathname_to_inode(ctx->vol, NULL, path); + if (!ni) + return -errno; + if (ntfs_readdir(ni, &pos, &fill_ctx, + (ntfs_filldir_t)ntfs_fuse_filler)) + err = -errno; + ntfs_fuse_update_times(ni, NTFS_UPDATE_ATIME); + if (ntfs_inode_close(ni)) + set_fuse_error(&err); + return err; +} + +static int ntfs_fuse_open(const char *org_path, +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + struct fuse_file_info *fi) +#else + struct fuse_file_info *fi __attribute__((unused))) +#endif +{ + ntfs_inode *ni; + ntfs_attr *na; + int res = 0; + char *path = NULL; + ntfschar *stream_name; + int stream_name_len; +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + int accesstype; + struct SECURITY_CONTEXT security; +#endif + + stream_name_len = ntfs_fuse_parse_path(org_path, &path, &stream_name); + if (stream_name_len < 0) + return stream_name_len; + ni = ntfs_pathname_to_inode(ctx->vol, NULL, path); + if (ni) { + na = ntfs_attr_open(ni, AT_DATA, stream_name, stream_name_len); + if (na) { +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + if (ntfs_fuse_fill_security_context(&security)) { + if (fi->flags & O_WRONLY) + accesstype = S_IWRITE; + else + if (fi->flags & O_RDWR) + accesstype = S_IWRITE | S_IREAD; + else + accesstype = S_IREAD; + /* + * directory must be searchable + * and requested access allowed + */ + if (!ntfs_allowed_dir_access(&security, + path,(ntfs_inode*)NULL,ni,S_IEXEC) + || !ntfs_allowed_access(&security, + ni,accesstype)) + res = -EACCES; + } +#endif + if ((res >= 0) + && (fi->flags & (O_WRONLY | O_RDWR))) { + /* mark a future need to compress the last chunk */ + if (na->data_flags & ATTR_COMPRESSION_MASK) + fi->fh |= CLOSE_COMPRESSED; +#ifdef HAVE_SETXATTR /* extended attributes interface required */ + /* mark a future need to fixup encrypted inode */ + if (ctx->efs_raw + && !(na->data_flags & ATTR_IS_ENCRYPTED) + && (ni->flags & FILE_ATTR_ENCRYPTED)) + fi->fh |= CLOSE_ENCRYPTED; +#endif /* HAVE_SETXATTR */ + } + ntfs_attr_close(na); + } else + res = -errno; + if (ntfs_inode_close(ni)) + set_fuse_error(&res); + } else + res = -errno; + free(path); + if (stream_name_len) + free(stream_name); + return res; +} + +static int ntfs_fuse_read(const char *org_path, char *buf, size_t size, + off_t offset, struct fuse_file_info *fi __attribute__((unused))) +{ + ntfs_inode *ni = NULL; + ntfs_attr *na = NULL; + char *path = NULL; + ntfschar *stream_name; + int stream_name_len, res; + s64 total = 0; + s64 max_read; + + if (!size) + return 0; + + stream_name_len = ntfs_fuse_parse_path(org_path, &path, &stream_name); + if (stream_name_len < 0) + return stream_name_len; + ni = ntfs_pathname_to_inode(ctx->vol, NULL, path); + if (!ni) { + res = -errno; + goto exit; + } + na = ntfs_attr_open(ni, AT_DATA, stream_name, stream_name_len); + if (!na) { + res = -errno; + goto exit; + } + max_read = na->data_size; +#ifdef HAVE_SETXATTR /* extended attributes interface required */ + /* limit reads at next 512 byte boundary for encrypted attributes */ + if (ctx->efs_raw && (na->data_flags & ATTR_IS_ENCRYPTED) && + NAttrNonResident(na)) { + max_read = ((na->data_size+511) & ~511) + 2; + } +#endif /* HAVE_SETXATTR */ + if (offset + (off_t)size > max_read) { + if (max_read < offset) + goto ok; + size = max_read - offset; + } + while (size > 0) { + s64 ret = ntfs_attr_pread(na, offset, size, buf + total); + if (ret != (s64)size) + ntfs_log_perror("ntfs_attr_pread error reading '%s' at " + "offset %lld: %lld <> %lld", org_path, + (long long)offset, (long long)size, (long long)ret); + if (ret <= 0 || ret > (s64)size) { + res = (ret < 0) ? -errno : -EIO; + goto exit; + } + size -= ret; + offset += ret; + total += ret; + } +ok: + ntfs_fuse_update_times(na->ni, NTFS_UPDATE_ATIME); + res = total; +exit: + if (na) + ntfs_attr_close(na); + if (ntfs_inode_close(ni)) + set_fuse_error(&res); + free(path); + if (stream_name_len) + free(stream_name); + return res; +} + +static int ntfs_fuse_write(const char *org_path, const char *buf, size_t size, + off_t offset, struct fuse_file_info *fi __attribute__((unused))) +{ + ntfs_inode *ni = NULL; + ntfs_attr *na = NULL; + char *path = NULL; + ntfschar *stream_name; + int stream_name_len, res, total = 0; + + stream_name_len = ntfs_fuse_parse_path(org_path, &path, &stream_name); + if (stream_name_len < 0) { + res = stream_name_len; + goto out; + } + ni = ntfs_pathname_to_inode(ctx->vol, NULL, path); + if (!ni) { + res = -errno; + goto exit; + } + na = ntfs_attr_open(ni, AT_DATA, stream_name, stream_name_len); + if (!na) { + res = -errno; + goto exit; + } + while (size) { + s64 ret = ntfs_attr_pwrite(na, offset, size, buf + total); + if (ret <= 0) { + res = -errno; + goto exit; + } + size -= ret; + offset += ret; + total += ret; + } + res = total; + if (res > 0) + ntfs_fuse_update_times(na->ni, NTFS_UPDATE_MCTIME); +exit: + if (na) + ntfs_attr_close(na); + if (total) + set_archive(ni); + if (ntfs_inode_close(ni)) + set_fuse_error(&res); + free(path); + if (stream_name_len) + free(stream_name); +out: + return res; +} + +static int ntfs_fuse_release(const char *org_path, + struct fuse_file_info *fi) +{ + ntfs_inode *ni = NULL; + ntfs_attr *na = NULL; + char *path = NULL; + ntfschar *stream_name; + int stream_name_len, res; + + /* Only for marked descriptors there is something to do */ + if (!(fi->fh & (CLOSE_COMPRESSED | CLOSE_ENCRYPTED))) { + res = 0; + goto out; + } + stream_name_len = ntfs_fuse_parse_path(org_path, &path, &stream_name); + if (stream_name_len < 0) { + res = stream_name_len; + goto out; + } + ni = ntfs_pathname_to_inode(ctx->vol, NULL, path); + if (!ni) { + res = -errno; + goto exit; + } + na = ntfs_attr_open(ni, AT_DATA, stream_name, stream_name_len); + if (!na) { + res = -errno; + goto exit; + } + res = 0; + if (fi->fh & CLOSE_COMPRESSED) + res = ntfs_attr_pclose(na); +#ifdef HAVE_SETXATTR /* extended attributes interface required */ + if (fi->fh & CLOSE_ENCRYPTED) + res = ntfs_efs_fixup_attribute(NULL, na); +#endif /* HAVE_SETXATTR */ +exit: + if (na) + ntfs_attr_close(na); + if (ntfs_inode_close(ni)) + set_fuse_error(&res); + free(path); + if (stream_name_len) + free(stream_name); +out: + return res; +} + +/* + * Common part for truncate() and ftruncate() + */ + +static int ntfs_fuse_trunc(const char *org_path, off_t size, +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + BOOL chkwrite) +#else + BOOL chkwrite __attribute__((unused))) +#endif +{ + ntfs_inode *ni = NULL; + ntfs_attr *na = NULL; + int res; + char *path = NULL; + ntfschar *stream_name; + int stream_name_len; + s64 oldsize; +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + struct SECURITY_CONTEXT security; +#endif + + stream_name_len = ntfs_fuse_parse_path(org_path, &path, &stream_name); + if (stream_name_len < 0) + return stream_name_len; + ni = ntfs_pathname_to_inode(ctx->vol, NULL, path); + if (!ni) + goto exit; + + na = ntfs_attr_open(ni, AT_DATA, stream_name, stream_name_len); + if (!na) + goto exit; +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + /* + * JPA deny truncation if cannot search in parent directory + * or cannot write to file (already checked for ftruncate()) + */ + if (ntfs_fuse_fill_security_context(&security) + && (!ntfs_allowed_dir_access(&security, path, + (ntfs_inode*)NULL, ni, S_IEXEC) + || (chkwrite + && !ntfs_allowed_access(&security, ni, S_IWRITE)))) { + errno = EACCES; + goto exit; + } +#endif + /* + * for compressed files, only deleting contents and expanding + * are implemented. Expanding is done by inserting a final + * zero, which is optimized as creating a hole when possible. + */ + if ((na->data_flags & ATTR_COMPRESSION_MASK) + && size + && (size < na->initialized_size)) { + errno = EOPNOTSUPP; + goto exit; + } + oldsize = na->data_size; + if ((na->data_flags & ATTR_COMPRESSION_MASK) + && (size > na->initialized_size)) { + char zero = 0; + if (ntfs_attr_pwrite(na, size - 1, 1, &zero) <= 0) + goto exit; + } else + if (ntfs_attr_truncate(na, size)) + goto exit; + if (oldsize != size) + set_archive(ni); + + ntfs_fuse_update_times(na->ni, NTFS_UPDATE_MCTIME); + errno = 0; +exit: + res = -errno; + ntfs_attr_close(na); + if (ntfs_inode_close(ni)) + set_fuse_error(&res); + free(path); + if (stream_name_len) + free(stream_name); + return res; +} + +static int ntfs_fuse_truncate(const char *org_path, off_t size) +{ + return ntfs_fuse_trunc(org_path, size, TRUE); +} + +static int ntfs_fuse_ftruncate(const char *org_path, off_t size, + struct fuse_file_info *fi __attribute__((unused))) +{ + /* + * in ->ftruncate() the file handle is guaranteed + * to have been opened for write. + */ + return (ntfs_fuse_trunc(org_path, size, FALSE)); +} + +static int ntfs_fuse_chmod(const char *path, + mode_t mode) +{ + int res = 0; + ntfs_inode *ni; + struct SECURITY_CONTEXT security; + + if (ntfs_fuse_is_named_data_stream(path)) + return -EINVAL; /* n/a for named data streams. */ + + /* JPA return unsupported if no user mapping has been defined */ + if (!ntfs_fuse_fill_security_context(&security)) { + if (ctx->silent) + res = 0; + else + res = -EOPNOTSUPP; + } else { +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + /* parent directory must be executable */ + if (ntfs_allowed_dir_access(&security,path, + (ntfs_inode*)NULL,(ntfs_inode*)NULL,S_IEXEC)) { +#endif + ni = ntfs_pathname_to_inode(ctx->vol, NULL, path); + if (!ni) + res = -errno; + else { + if (ntfs_set_mode(&security,ni,mode)) + res = -errno; + else + ntfs_fuse_update_times(ni, NTFS_UPDATE_CTIME); + NInoSetDirty(ni); + if (ntfs_inode_close(ni)) + set_fuse_error(&res); + } +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + } else + res = -errno; +#endif + } + return res; +} + +static int ntfs_fuse_chown(const char *path, uid_t uid, gid_t gid) +{ + ntfs_inode *ni; + int res; + struct SECURITY_CONTEXT security; + + if (ntfs_fuse_is_named_data_stream(path)) + return -EINVAL; /* n/a for named data streams. */ + if (!ntfs_fuse_fill_security_context(&security)) { + if (ctx->silent) + return 0; + if (uid == ctx->uid && gid == ctx->gid) + return 0; + return -EOPNOTSUPP; + } else { + res = 0; + if (((int)uid != -1) || ((int)gid != -1)) { +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + /* parent directory must be executable */ + + if (ntfs_allowed_dir_access(&security,path, + (ntfs_inode*)NULL,(ntfs_inode*)NULL,S_IEXEC)) { +#endif + ni = ntfs_pathname_to_inode(ctx->vol, NULL, path); + if (!ni) + res = -errno; + else { + if (ntfs_set_owner(&security, + ni,uid,gid)) + res = -errno; + else + ntfs_fuse_update_times(ni, NTFS_UPDATE_CTIME); + if (ntfs_inode_close(ni)) + set_fuse_error(&res); + } +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + } else + res = -errno; +#endif + } + } + return (res); +} + +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + +static int ntfs_fuse_access(const char *path, int type) +{ + int res = 0; + int mode; + ntfs_inode *ni; + struct SECURITY_CONTEXT security; + + if (ntfs_fuse_is_named_data_stream(path)) + return -EINVAL; /* n/a for named data streams. */ + + /* JPA return unsupported if no user mapping has been defined */ + if (!ntfs_fuse_fill_security_context(&security)) { + if (ctx->silent) + res = 0; + else + res = -EOPNOTSUPP; + } else { + /* parent directory must be seachable */ + if (ntfs_allowed_dir_access(&security,path,(ntfs_inode*)NULL, + (ntfs_inode*)NULL,S_IEXEC)) { + ni = ntfs_pathname_to_inode(ctx->vol, NULL, path); + if (!ni) { + res = -errno; + } else { + mode = 0; + if (type & (X_OK | W_OK | R_OK)) { + if (type & X_OK) mode += S_IEXEC; + if (type & W_OK) mode += S_IWRITE; + if (type & R_OK) mode += S_IREAD; + if (!ntfs_allowed_access(&security, + ni, mode)) + res = -errno; + } + if (ntfs_inode_close(ni)) + set_fuse_error(&res); + } + } else + res = -errno; + } + return (res); +} + +#endif + +static int ntfs_fuse_create(const char *org_path, mode_t typemode, dev_t dev, + const char *target, struct fuse_file_info *fi) +{ + char *name; + ntfschar *uname = NULL, *utarget = NULL; + ntfs_inode *dir_ni = NULL, *ni; + char *dir_path; + le32 securid; + char *path; + ntfschar *stream_name; + int stream_name_len; + mode_t type = typemode & ~07777; + mode_t perm; + struct SECURITY_CONTEXT security; + int res = 0, uname_len, utarget_len; + + dir_path = strdup(org_path); + if (!dir_path) + return -errno; + /* Generate unicode filename. */ + name = strrchr(dir_path, '/'); + name++; + uname_len = ntfs_mbstoucs(name, &uname); + if (uname_len < 0) { + res = -errno; + goto exit; + } + stream_name_len = ntfs_fuse_parse_path(org_path, + &path, &stream_name); + if (stream_name_len < 0) { + res = stream_name_len; + goto exit; + } + /* Open parent directory. */ + *--name = 0; + dir_ni = ntfs_pathname_to_inode(ctx->vol, NULL, dir_path); + if (!dir_ni) { + free(path); + res = -errno; + goto exit; + } +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + /* make sure parent directory is writeable and executable */ + if (!ntfs_fuse_fill_security_context(&security) + || ntfs_allowed_access(&security, + dir_ni,S_IWRITE + S_IEXEC)) { +#else + ntfs_fuse_fill_security_context(&security); +#endif + if (S_ISDIR(type)) + perm = typemode & ~ctx->dmask & 0777; + else + perm = typemode & ~ctx->fmask & 0777; + /* + * Try to get a security id available for + * file creation (from inheritance or argument). + * This is not possible for NTFS 1.x, and we will + * have to build a security attribute later. + */ + if (!ctx->security.mapping[MAPUSERS]) + securid = 0; + else + if (ctx->inherit) + securid = ntfs_inherited_id(&security, + dir_ni, S_ISDIR(type)); + else +#if POSIXACLS + securid = ntfs_alloc_securid(&security, + security.uid, security.gid, + dir_ni, perm, S_ISDIR(type)); +#else + securid = ntfs_alloc_securid(&security, + security.uid, security.gid, + perm & ~security.umask, S_ISDIR(type)); +#endif + /* Create object specified in @type. */ + switch (type) { + case S_IFCHR: + case S_IFBLK: + ni = ntfs_create_device(dir_ni, securid, + uname, uname_len, type, dev); + break; + case S_IFLNK: + utarget_len = ntfs_mbstoucs(target, &utarget); + if (utarget_len < 0) { + res = -errno; + goto exit; + } + ni = ntfs_create_symlink(dir_ni, securid, + uname, uname_len, + utarget, utarget_len); + break; + default: + ni = ntfs_create(dir_ni, securid, uname, + uname_len, type); + break; + } + if (ni) { + /* + * set the security attribute if a security id + * could not be allocated (eg NTFS 1.x) + */ + if (ctx->security.mapping[MAPUSERS]) { +#if POSIXACLS + if (!securid + && ntfs_set_inherited_posix(&security, ni, + security.uid, security.gid, + dir_ni, perm) < 0) + set_fuse_error(&res); +#else + if (!securid + && ntfs_set_owner_mode(&security, ni, + security.uid, security.gid, + perm & ~security.umask) < 0) + set_fuse_error(&res); +#endif + } + set_archive(ni); + /* mark a need to compress the end of file */ + if (fi && (ni->flags & FILE_ATTR_COMPRESSED)) { + fi->fh |= CLOSE_COMPRESSED; + } +#ifdef HAVE_SETXATTR /* extended attributes interface required */ + /* mark a future need to fixup encrypted inode */ + if (fi + && ctx->efs_raw + && (ni->flags & FILE_ATTR_ENCRYPTED)) + fi->fh |= CLOSE_ENCRYPTED; +#endif /* HAVE_SETXATTR */ + NInoSetDirty(ni); + /* + * closing ni requires access to dir_ni to + * synchronize the index, avoid double opening. + */ + if (ntfs_inode_close_in_dir(ni, dir_ni)) + set_fuse_error(&res); + ntfs_fuse_update_times(dir_ni, NTFS_UPDATE_MCTIME); + } else + res = -errno; +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + } else + res = -errno; +#endif + free(path); + +exit: + free(uname); + if (ntfs_inode_close(dir_ni)) + set_fuse_error(&res); + if (utarget) + free(utarget); + free(dir_path); + return res; +} + +static int ntfs_fuse_create_stream(const char *path, + ntfschar *stream_name, const int stream_name_len, + struct fuse_file_info *fi) +{ + ntfs_inode *ni; + int res = 0; + + ni = ntfs_pathname_to_inode(ctx->vol, NULL, path); + if (!ni) { + res = -errno; + if (res == -ENOENT) { + /* + * If such file does not exist, create it and try once + * again to add stream to it. + * Note : no fuse_file_info for creation of main file + */ + res = ntfs_fuse_create(path, S_IFREG, 0, NULL, + (struct fuse_file_info*)NULL); + if (!res) + return ntfs_fuse_create_stream(path, + stream_name, stream_name_len,fi); + else + res = -errno; + } + return res; + } + if (ntfs_attr_add(ni, AT_DATA, stream_name, stream_name_len, NULL, 0)) + res = -errno; + + if ((res >= 0) + && (fi->flags & (O_WRONLY | O_RDWR))) { + set_archive(ni); + /* mark a future need to compress the last block */ + if (ni->flags & FILE_ATTR_COMPRESSED) + fi->fh |= CLOSE_COMPRESSED; +#ifdef HAVE_SETXATTR /* extended attributes interface required */ + /* mark a future need to fixup encrypted inode */ + if (ctx->efs_raw + && (ni->flags & FILE_ATTR_ENCRYPTED)) + fi->fh |= CLOSE_ENCRYPTED; +#endif /* HAVE_SETXATTR */ + } + + if (ntfs_inode_close(ni)) + set_fuse_error(&res); + return res; +} + +static int ntfs_fuse_mknod_common(const char *org_path, mode_t mode, dev_t dev, + struct fuse_file_info *fi) +{ + char *path = NULL; + ntfschar *stream_name; + int stream_name_len; + int res = 0; + + stream_name_len = ntfs_fuse_parse_path(org_path, &path, &stream_name); + if (stream_name_len < 0) + return stream_name_len; + if (stream_name_len && !S_ISREG(mode)) { + res = -EINVAL; + goto exit; + } + if (!stream_name_len) + res = ntfs_fuse_create(path, mode & (S_IFMT | 07777), dev, + NULL,fi); + else + res = ntfs_fuse_create_stream(path, stream_name, + stream_name_len,fi); +exit: + free(path); + if (stream_name_len) + free(stream_name); + return res; +} + +static int ntfs_fuse_mknod(const char *path, mode_t mode, dev_t dev) +{ + return ntfs_fuse_mknod_common(path, mode, dev, + (struct fuse_file_info*)NULL); +} + +static int ntfs_fuse_create_file(const char *path, mode_t mode, + struct fuse_file_info *fi) +{ + return ntfs_fuse_mknod_common(path, mode, 0, fi); +} + +static int ntfs_fuse_symlink(const char *to, const char *from) +{ + if (ntfs_fuse_is_named_data_stream(from)) + return -EINVAL; /* n/a for named data streams. */ + return ntfs_fuse_create(from, S_IFLNK, 0, to, + (struct fuse_file_info*)NULL); +} + +static int ntfs_fuse_link(const char *old_path, const char *new_path) +{ + char *name; + ntfschar *uname = NULL; + ntfs_inode *dir_ni = NULL, *ni; + char *path; + int res = 0, uname_len; +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + BOOL samedir; + struct SECURITY_CONTEXT security; +#endif + + if (ntfs_fuse_is_named_data_stream(old_path)) + return -EINVAL; /* n/a for named data streams. */ + if (ntfs_fuse_is_named_data_stream(new_path)) + return -EINVAL; /* n/a for named data streams. */ + path = strdup(new_path); + if (!path) + return -errno; + /* Open file for which create hard link. */ + ni = ntfs_pathname_to_inode(ctx->vol, NULL, old_path); + if (!ni) { + res = -errno; + goto exit; + } + + /* Generate unicode filename. */ + name = strrchr(path, '/'); + name++; + uname_len = ntfs_mbstoucs(name, &uname); + if (uname_len < 0) { + res = -errno; + goto exit; + } + /* Open parent directory. */ + *--name = 0; + dir_ni = ntfs_pathname_to_inode(ctx->vol, NULL, path); + if (!dir_ni) { + res = -errno; + goto exit; + } + +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + samedir = !strncmp(old_path, path, strlen(path)) + && (old_path[strlen(path)] == '/'); + /* JPA make sure the parent directories are writeable */ + if (ntfs_fuse_fill_security_context(&security) + && ((!samedir && !ntfs_allowed_dir_access(&security,old_path, + (ntfs_inode*)NULL,ni,S_IWRITE + S_IEXEC)) + || !ntfs_allowed_access(&security,dir_ni,S_IWRITE + S_IEXEC))) + res = -EACCES; + else +#endif + { + if (ntfs_link(ni, dir_ni, uname, uname_len)) { + res = -errno; + goto exit; + } + + set_archive(ni); + ntfs_fuse_update_times(ni, NTFS_UPDATE_CTIME); + ntfs_fuse_update_times(dir_ni, NTFS_UPDATE_MCTIME); + } +exit: + /* + * Must close dir_ni first otherwise ntfs_inode_sync_file_name(ni) + * may fail because ni may not be in parent's index on the disk yet. + */ + if (ntfs_inode_close(dir_ni)) + set_fuse_error(&res); + if (ntfs_inode_close(ni)) + set_fuse_error(&res); + free(uname); + free(path); + return res; +} + +static int ntfs_fuse_rm(const char *org_path) +{ + char *name; + ntfschar *uname = NULL; + ntfs_inode *dir_ni = NULL, *ni; + char *path; + int res = 0, uname_len; +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + struct SECURITY_CONTEXT security; +#endif + + path = strdup(org_path); + if (!path) + return -errno; + /* Open object for delete. */ + ni = ntfs_pathname_to_inode(ctx->vol, NULL, path); + if (!ni) { + res = -errno; + goto exit; + } + /* Generate unicode filename. */ + name = strrchr(path, '/'); + name++; + uname_len = ntfs_mbstoucs(name, &uname); + if (uname_len < 0) { + res = -errno; + goto exit; + } + /* Open parent directory. */ + *--name = 0; + dir_ni = ntfs_pathname_to_inode(ctx->vol, NULL, path); + if (!dir_ni) { + res = -errno; + goto exit; + } + +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + /* JPA deny unlinking if directory is not writable and executable */ + if (!ntfs_fuse_fill_security_context(&security) + || ntfs_allowed_dir_access(&security, org_path, dir_ni, ni, + S_IEXEC + S_IWRITE + S_ISVTX)) { +#endif + if (ntfs_delete(ctx->vol, org_path, ni, dir_ni, + uname, uname_len)) + res = -errno; + /* ntfs_delete() always closes ni and dir_ni */ + ni = dir_ni = NULL; +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + } else + res = -EACCES; +#endif +exit: + if (ntfs_inode_close(dir_ni)) + set_fuse_error(&res); + if (ntfs_inode_close(ni)) + set_fuse_error(&res); + free(uname); + free(path); + return res; +} + +static int ntfs_fuse_rm_stream(const char *path, ntfschar *stream_name, + const int stream_name_len) +{ + ntfs_inode *ni; + int res = 0; + + ni = ntfs_pathname_to_inode(ctx->vol, NULL, path); + if (!ni) + return -errno; + + if (ntfs_attr_remove(ni, AT_DATA, stream_name, stream_name_len)) + res = -errno; + + if (ntfs_inode_close(ni)) + set_fuse_error(&res); + return res; +} + +static int ntfs_fuse_unlink(const char *org_path) +{ + char *path = NULL; + ntfschar *stream_name; + int stream_name_len; + int res = 0; +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + struct SECURITY_CONTEXT security; +#endif + + stream_name_len = ntfs_fuse_parse_path(org_path, &path, &stream_name); + if (stream_name_len < 0) + return stream_name_len; + if (!stream_name_len) + res = ntfs_fuse_rm(path); + else { +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + /* + * JPA deny unlinking stream if directory is not + * writable and executable (debatable) + */ + if (!ntfs_fuse_fill_security_context(&security) + || ntfs_allowed_dir_access(&security, path, + (ntfs_inode*)NULL, (ntfs_inode*)NULL, + S_IEXEC + S_IWRITE + S_ISVTX)) + res = ntfs_fuse_rm_stream(path, stream_name, + stream_name_len); + else + res = -errno; +#else + res = ntfs_fuse_rm_stream(path, stream_name, stream_name_len); +#endif + } + free(path); + if (stream_name_len) + free(stream_name); + return res; +} + +static int ntfs_fuse_safe_rename(const char *old_path, + const char *new_path, + const char *tmp) +{ + int ret; + + ntfs_log_trace("Entering\n"); + + ret = ntfs_fuse_link(new_path, tmp); + if (ret) + return ret; + + ret = ntfs_fuse_unlink(new_path); + if (!ret) { + + ret = ntfs_fuse_link(old_path, new_path); + if (ret) + goto restore; + + ret = ntfs_fuse_unlink(old_path); + if (ret) { + if (ntfs_fuse_unlink(new_path)) + goto err; + goto restore; + } + } + + goto cleanup; +restore: + if (ntfs_fuse_link(tmp, new_path)) { +err: + ntfs_log_perror("Rename failed. Existing file '%s' was renamed " + "to '%s'", new_path, tmp); + } else { +cleanup: + /* + * Condition for this unlink has already been checked in + * "ntfs_fuse_rename_existing_dest()", so it should never + * fail (unless concurrent access to directories when fuse + * is multithreaded) + */ + if (ntfs_fuse_unlink(tmp) < 0) + ntfs_log_perror("Rename failed. Existing file '%s' still present " + "as '%s'", new_path, tmp); + } + return ret; +} + +static int ntfs_fuse_rename_existing_dest(const char *old_path, const char *new_path) +{ + int ret, len; + char *tmp; + const char *ext = ".ntfs-3g-"; +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + struct SECURITY_CONTEXT security; +#endif + + ntfs_log_trace("Entering\n"); + + len = strlen(new_path) + strlen(ext) + 10 + 1; /* wc(str(2^32)) + \0 */ + tmp = ntfs_malloc(len); + if (!tmp) + return -errno; + + ret = snprintf(tmp, len, "%s%s%010d", new_path, ext, ++ntfs_sequence); + if (ret != len - 1) { + ntfs_log_error("snprintf failed: %d != %d\n", ret, len - 1); + ret = -EOVERFLOW; + } else { +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + /* + * Make sure existing dest can be removed. + * This is only needed if parent directory is + * sticky, because in this situation condition + * for unlinking is different from condition for + * linking + */ + if (!ntfs_fuse_fill_security_context(&security) + || ntfs_allowed_dir_access(&security, new_path, + (ntfs_inode*)NULL, (ntfs_inode*)NULL, + S_IEXEC + S_IWRITE + S_ISVTX)) + ret = ntfs_fuse_safe_rename(old_path, new_path, tmp); + else + ret = -EACCES; +#else + ret = ntfs_fuse_safe_rename(old_path, new_path, tmp); +#endif + } + free(tmp); + return ret; +} + +static int ntfs_fuse_rename(const char *old_path, const char *new_path) +{ + int ret, stream_name_len; + char *path = NULL; + ntfschar *stream_name; + ntfs_inode *ni; + u64 inum; + BOOL same; + + ntfs_log_debug("rename: old: '%s' new: '%s'\n", old_path, new_path); + + /* + * FIXME: Rename should be atomic. + */ + stream_name_len = ntfs_fuse_parse_path(new_path, &path, &stream_name); + if (stream_name_len < 0) + return stream_name_len; + + ni = ntfs_pathname_to_inode(ctx->vol, NULL, path); + if (ni) { + ret = ntfs_check_empty_dir(ni); + if (ret < 0) { + ret = -errno; + ntfs_inode_close(ni); + goto out; + } + + inum = ni->mft_no; + if (ntfs_inode_close(ni)) { + set_fuse_error(&ret); + goto out; + } + + free(path); + path = (char*)NULL; + if (stream_name_len) + free(stream_name); + + /* silently ignore a rename to same inode */ + stream_name_len = ntfs_fuse_parse_path(old_path, + &path, &stream_name); + if (stream_name_len < 0) + return stream_name_len; + + ni = ntfs_pathname_to_inode(ctx->vol, NULL, path); + if (ni) { + same = ni->mft_no == inum; + if (ntfs_inode_close(ni)) + ret = -errno; + else + if (!same) + ret = ntfs_fuse_rename_existing_dest( + old_path, new_path); + } else + ret = -errno; + goto out; + } + + ret = ntfs_fuse_link(old_path, new_path); + if (ret) + goto out; + + ret = ntfs_fuse_unlink(old_path); + if (ret) + ntfs_fuse_unlink(new_path); +out: + free(path); + if (stream_name_len) + free(stream_name); + return ret; +} + +static int ntfs_fuse_mkdir(const char *path, + mode_t mode) +{ + if (ntfs_fuse_is_named_data_stream(path)) + return -EINVAL; /* n/a for named data streams. */ + return ntfs_fuse_create(path, S_IFDIR | (mode & 07777), 0, NULL, + (struct fuse_file_info*)NULL); +} + +static int ntfs_fuse_rmdir(const char *path) +{ + if (ntfs_fuse_is_named_data_stream(path)) + return -EINVAL; /* n/a for named data streams. */ + return ntfs_fuse_rm(path); +} + +#ifdef HAVE_UTIMENSAT + +static int ntfs_fuse_utimens(const char *path, const struct timespec tv[2]) +{ + ntfs_inode *ni; + int res = 0; +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + struct SECURITY_CONTEXT security; +#endif + + if (ntfs_fuse_is_named_data_stream(path)) + return -EINVAL; /* n/a for named data streams. */ +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + /* parent directory must be executable */ + if (ntfs_fuse_fill_security_context(&security) + && !ntfs_allowed_dir_access(&security,path, + (ntfs_inode*)NULL,(ntfs_inode*)NULL,S_IEXEC)) { + return (-errno); + } +#endif + ni = ntfs_pathname_to_inode(ctx->vol, NULL, path); + if (!ni) + return -errno; + + /* no check or update if both UTIME_OMIT */ + if ((tv[0].tv_nsec != UTIME_OMIT) || (tv[1].tv_nsec != UTIME_OMIT)) { +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + if (ntfs_allowed_as_owner(&security, ni) + || ((tv[0].tv_nsec == UTIME_NOW) + && (tv[0].tv_nsec == UTIME_NOW) + && ntfs_allowed_access(&security, ni, S_IWRITE))) { +#endif + ntfs_time_update_flags mask = NTFS_UPDATE_CTIME; + + if (tv[0].tv_nsec == UTIME_NOW) + mask |= NTFS_UPDATE_ATIME; + else + if (tv[0].tv_nsec != UTIME_OMIT) + ni->last_access_time + = timespec2ntfs(tv[0]); + if (tv[1].tv_nsec == UTIME_NOW) + mask |= NTFS_UPDATE_MTIME; + else + if (tv[1].tv_nsec != UTIME_OMIT) + ni->last_data_change_time + = timespec2ntfs(tv[1]); + ntfs_inode_update_times(ni, mask); +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + } else + res = -errno; +#endif + } + if (ntfs_inode_close(ni)) + set_fuse_error(&res); + return res; +} + +#else /* HAVE_UTIMENSAT */ + +static int ntfs_fuse_utime(const char *path, struct utimbuf *buf) +{ + ntfs_inode *ni; + int res = 0; + struct timespec actime; + struct timespec modtime; +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + BOOL ownerok; + BOOL writeok; + struct SECURITY_CONTEXT security; +#endif + + if (ntfs_fuse_is_named_data_stream(path)) + return -EINVAL; /* n/a for named data streams. */ +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + /* parent directory must be executable */ + if (ntfs_fuse_fill_security_context(&security) + && !ntfs_allowed_dir_access(&security,path, + (ntfs_inode*)NULL,(ntfs_inode*)NULL,S_IEXEC)) { + return (-errno); + } +#endif + ni = ntfs_pathname_to_inode(ctx->vol, NULL, path); + if (!ni) + return -errno; + +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + ownerok = ntfs_allowed_as_owner(&security, ni); + if (buf) { + /* + * fuse never calls with a NULL buf and we do not + * know whether the specific condition can be applied + * So we have to accept updating by a non-owner having + * write access. + */ + writeok = !ownerok + && (buf->actime == buf->modtime) + && ntfs_allowed_access(&security, ni, S_IWRITE); + /* Must be owner */ + if (!ownerok && !writeok) + res = (buf->actime == buf->modtime ? -EACCES : -EPERM); + else { + actime.tv_sec = buf->actime; + actime.tv_nsec = 0; + modtime.tv_sec = buf->modtime; + modtime.tv_nsec = 0; + ni->last_access_time = timespec2ntfs(actime); + ni->last_data_change_time = timespec2ntfs(modtime); + ntfs_fuse_update_times(ni, NTFS_UPDATE_CTIME); + } + } else { + /* Must be owner or have write access */ + writeok = !ownerok + && ntfs_allowed_access(&security, ni, S_IWRITE); + if (!ownerok && !writeok) + res = -EACCES; + else + ntfs_inode_update_times(ni, NTFS_UPDATE_AMCTIME); + } +#else + if (buf) { + actime.tv_sec = buf->actime; + actime.tv_nsec = 0; + modtime.tv_sec = buf->modtime; + modtime.tv_nsec = 0; + ni->last_access_time = timespec2ntfs(actime); + ni->last_data_change_time = timespec2ntfs(modtime); + ntfs_fuse_update_times(ni, NTFS_UPDATE_CTIME); + } else + ntfs_inode_update_times(ni, NTFS_UPDATE_AMCTIME); +#endif + + if (ntfs_inode_close(ni)) + set_fuse_error(&res); + return res; +} + +#endif /* HAVE_UTIMENSAT */ + +static int ntfs_fuse_bmap(const char *path, size_t blocksize, uint64_t *idx) +{ + ntfs_inode *ni; + ntfs_attr *na; + LCN lcn; + int ret = 0; + int cl_per_bl = ctx->vol->cluster_size / blocksize; + + if (blocksize > ctx->vol->cluster_size) + return -EINVAL; + + if (ntfs_fuse_is_named_data_stream(path)) + return -EINVAL; + + ni = ntfs_pathname_to_inode(ctx->vol, NULL, path); + if (!ni) + return -errno; + + na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0); + if (!na) { + ret = -errno; + goto close_inode; + } + + if ((na->data_flags & (ATTR_COMPRESSION_MASK | ATTR_IS_ENCRYPTED)) + || !NAttrNonResident(na)) { + ret = -EINVAL; + goto close_attr; + } + + if (ntfs_attr_map_whole_runlist(na)) { + ret = -errno; + goto close_attr; + } + + lcn = ntfs_rl_vcn_to_lcn(na->rl, *idx / cl_per_bl); + *idx = (lcn > 0) ? lcn * cl_per_bl + *idx % cl_per_bl : 0; + +close_attr: + ntfs_attr_close(na); +close_inode: + if (ntfs_inode_close(ni)) + set_fuse_error(&ret); + return ret; +} + +#ifdef HAVE_SETXATTR + +/* + * Name space identifications and prefixes + */ + +enum { XATTRNS_NONE, + XATTRNS_USER, + XATTRNS_SYSTEM, + XATTRNS_SECURITY, + XATTRNS_TRUSTED, + XATTRNS_OPEN } ; + +static const char nf_ns_user_prefix[] = "user."; +static const int nf_ns_user_prefix_len = sizeof(nf_ns_user_prefix) - 1; +static const char nf_ns_system_prefix[] = "system."; +static const int nf_ns_system_prefix_len = sizeof(nf_ns_system_prefix) - 1; +static const char nf_ns_security_prefix[] = "security."; +static const int nf_ns_security_prefix_len = sizeof(nf_ns_security_prefix) - 1; +static const char nf_ns_trusted_prefix[] = "trusted."; +static const int nf_ns_trusted_prefix_len = sizeof(nf_ns_trusted_prefix) - 1; + +static const char xattr_ntfs_3g[] = "ntfs-3g."; + +/* + * Identification of data mapped to the system name space + */ + +enum { XATTR_UNMAPPED, + XATTR_NTFS_ACL, + XATTR_NTFS_ATTRIB, + XATTR_NTFS_EFSINFO, + XATTR_NTFS_REPARSE_DATA, + XATTR_NTFS_OBJECT_ID, + XATTR_NTFS_DOS_NAME, + XATTR_NTFS_TIMES, + XATTR_POSIX_ACC, + XATTR_POSIX_DEF } ; + +static const char nf_ns_xattr_ntfs_acl[] = "system.ntfs_acl"; +static const char nf_ns_xattr_attrib[] = "system.ntfs_attrib"; +static const char nf_ns_xattr_efsinfo[] = "user.ntfs.efsinfo"; +static const char nf_ns_xattr_reparse[] = "system.ntfs_reparse_data"; +static const char nf_ns_xattr_object_id[] = "system.ntfs_object_id"; +static const char nf_ns_xattr_dos_name[] = "system.ntfs_dos_name"; +static const char nf_ns_xattr_times[] = "system.ntfs_times"; +static const char nf_ns_xattr_posix_access[] = "system.posix_acl_access"; +static const char nf_ns_xattr_posix_default[] = "system.posix_acl_default"; + +struct XATTRNAME { + int xattr; + const char *name; +} ; + +static struct XATTRNAME nf_ns_xattr_names[] = { + { XATTR_NTFS_ACL, nf_ns_xattr_ntfs_acl }, + { XATTR_NTFS_ATTRIB, nf_ns_xattr_attrib }, + { XATTR_NTFS_EFSINFO, nf_ns_xattr_efsinfo }, + { XATTR_NTFS_REPARSE_DATA, nf_ns_xattr_reparse }, + { XATTR_NTFS_OBJECT_ID, nf_ns_xattr_object_id }, + { XATTR_NTFS_DOS_NAME, nf_ns_xattr_dos_name }, + { XATTR_NTFS_TIMES, nf_ns_xattr_times }, + { XATTR_POSIX_ACC, nf_ns_xattr_posix_access }, + { XATTR_POSIX_DEF, nf_ns_xattr_posix_default }, + { XATTR_UNMAPPED, (char*)NULL } /* terminator */ +}; + +/* + * Check whether access to internal data as an extended + * attribute in system name space is allowed + * + * Returns pointer to inode if allowed, + * NULL and errno set if not allowed + */ + +static ntfs_inode *ntfs_check_access_xattr(struct SECURITY_CONTEXT *security, + const char *path, int attr, BOOL setting) +{ + ntfs_inode *ni; + BOOL foracl; + mode_t acctype; + + ni = (ntfs_inode*)NULL; + if (ntfs_fuse_is_named_data_stream(path)) + errno = EINVAL; /* n/a for named data streams. */ + else { + foracl = (attr == XATTR_POSIX_ACC) + || (attr == XATTR_POSIX_DEF); + /* + * When accessing Posix ACL, return unsupported if ACL + * were disabled or no user mapping has been defined. + * However no error will be returned to getfacl + */ + if ((!ntfs_fuse_fill_security_context(security) + || (ctx->secure_flags + & ((1 << SECURITY_DEFAULT) | (1 << SECURITY_RAW)))) + && foracl) { + errno = EOPNOTSUPP; + } else { + /* + * parent directory must be executable, and + * for setting a DOS name it must be writeable + */ + if (setting && (attr == XATTR_NTFS_DOS_NAME)) + acctype = S_IEXEC | S_IWRITE; + else + acctype = S_IEXEC; + if ((attr == XATTR_NTFS_DOS_NAME) + && !strcmp(path,"/")) + /* forbid getting/setting names on root */ + errno = EPERM; + else + if (ntfs_allowed_real_dir_access(security, path, + (ntfs_inode*)NULL ,acctype)) { + ni = ntfs_pathname_to_inode(ctx->vol, + NULL, path); + } + } + } + return (ni); +} + +/* + * Determine whether an extended attribute is in the system + * name space and mapped to internal data + */ + +static int mapped_xattr_system(const char *name) +{ + struct XATTRNAME *p; + + p = nf_ns_xattr_names; + while (p->name && strcmp(p->name,name)) + p++; + return (p->xattr); +} + +/* + * Determine the name space of an extended attribute + */ + +static int xattr_namespace(const char *name) +{ + int namespace; + + if (ctx->streams == NF_STREAMS_INTERFACE_XATTR) { + namespace = XATTRNS_NONE; + if (!strncmp(name, nf_ns_user_prefix, + nf_ns_user_prefix_len) + && (strlen(name) != (size_t)nf_ns_user_prefix_len)) + namespace = XATTRNS_USER; + else if (!strncmp(name, nf_ns_system_prefix, + nf_ns_system_prefix_len) + && (strlen(name) != (size_t)nf_ns_system_prefix_len)) + namespace = XATTRNS_SYSTEM; + else if (!strncmp(name, nf_ns_security_prefix, + nf_ns_security_prefix_len) + && (strlen(name) != (size_t)nf_ns_security_prefix_len)) + namespace = XATTRNS_SECURITY; + else if (!strncmp(name, nf_ns_trusted_prefix, + nf_ns_trusted_prefix_len) + && (strlen(name) != (size_t)nf_ns_trusted_prefix_len)) + namespace = XATTRNS_TRUSTED; + } else + namespace = XATTRNS_OPEN; + return (namespace); +} + +/* + * Fix the prefix of an extended attribute + */ + +static int fix_xattr_prefix(const char *name, int namespace, ntfschar **lename) +{ + int len; + char *prefixed; + + *lename = (ntfschar*)NULL; + switch (namespace) { + case XATTRNS_USER : + /* + * user name space : remove user prefix + */ + len = ntfs_mbstoucs(name + nf_ns_user_prefix_len, lename); + break; + case XATTRNS_SYSTEM : + case XATTRNS_SECURITY : + case XATTRNS_TRUSTED : + /* + * security, trusted and unmapped system name spaces : + * insert ntfs-3g prefix + */ + prefixed = ntfs_malloc(strlen(xattr_ntfs_3g) + + strlen(name) + 1); + if (prefixed) { + strcpy(prefixed,xattr_ntfs_3g); + strcat(prefixed,name); + len = ntfs_mbstoucs(prefixed, lename); + free(prefixed); + } else + len = -1; + break; + case XATTRNS_OPEN : + /* + * in open name space mode : do no fix prefix + */ + len = ntfs_mbstoucs(name, lename); + break; + default : + len = -1; + } + return (len); +} + +static int ntfs_fuse_listxattr(const char *path, char *list, size_t size) +{ + ntfs_attr_search_ctx *actx = NULL; + ntfs_inode *ni; + char *to = list; + int ret = 0; +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + struct SECURITY_CONTEXT security; +#endif +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + /* parent directory must be executable */ + if (ntfs_fuse_fill_security_context(&security) + && !ntfs_allowed_dir_access(&security,path,(ntfs_inode*)NULL, + (ntfs_inode*)NULL,S_IEXEC)) { + return (-errno); + } +#endif + ni = ntfs_pathname_to_inode(ctx->vol, NULL, path); + if (!ni) + return -errno; +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + /* file must be readable */ + if (!ntfs_allowed_access(&security,ni,S_IREAD)) { + ret = -EACCES; + goto exit; + } +#endif + actx = ntfs_attr_get_search_ctx(ni, NULL); + if (!actx) { + ret = -errno; + goto exit; + } + + if ((ctx->streams == NF_STREAMS_INTERFACE_XATTR) + || (ctx->streams == NF_STREAMS_INTERFACE_OPENXATTR)) { + while (!ntfs_attr_lookup(AT_DATA, NULL, 0, CASE_SENSITIVE, + 0, NULL, 0, actx)) { + char *tmp_name = NULL; + int tmp_name_len; + + if (!actx->attr->name_length) + continue; + tmp_name_len = ntfs_ucstombs( + (ntfschar *)((u8*)actx->attr + + le16_to_cpu(actx->attr->name_offset)), + actx->attr->name_length, &tmp_name, 0); + if (tmp_name_len < 0) { + ret = -errno; + goto exit; + } + /* + * When using name spaces, do not return + * security, trusted nor system attributes + * (filtered elsewhere anyway) + * otherwise insert "user." prefix + */ + if (ctx->streams == NF_STREAMS_INTERFACE_XATTR) { + if ((strlen(tmp_name) > sizeof(xattr_ntfs_3g)) + && !strncmp(tmp_name,xattr_ntfs_3g, + sizeof(xattr_ntfs_3g)-1)) + tmp_name_len = 0; + else + ret += tmp_name_len + + nf_ns_user_prefix_len + 1; + } else + ret += tmp_name_len + 1; + if (size && tmp_name_len) { + if ((size_t)ret <= size) { + if (ctx->streams + == NF_STREAMS_INTERFACE_XATTR) { + strcpy(to, nf_ns_user_prefix); + to += nf_ns_user_prefix_len; + } + strncpy(to, tmp_name, tmp_name_len); + to += tmp_name_len; + *to = 0; + to++; + } else { + free(tmp_name); + ret = -ERANGE; + goto exit; + } + } + free(tmp_name); + } + } + + /* List efs info xattr for encrypted files */ + if (ctx->efs_raw && (ni->flags & FILE_ATTR_ENCRYPTED)) { + ret += sizeof(nf_ns_xattr_efsinfo); + if ((size_t)ret <= size) { + memcpy(to, nf_ns_xattr_efsinfo, + sizeof(nf_ns_xattr_efsinfo)); + to += sizeof(nf_ns_xattr_efsinfo); + } + } + + if (errno != ENOENT) + ret = -errno; +exit: + if (actx) + ntfs_attr_put_search_ctx(actx); + if (ntfs_inode_close(ni)) + set_fuse_error(&ret); + return ret; +} + +static int ntfs_fuse_getxattr_windows(const char *path, const char *name, + char *value, size_t size) +{ + ntfs_attr_search_ctx *actx = NULL; + ntfs_inode *ni; + char *to = value; + int ret = 0; +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + struct SECURITY_CONTEXT security; +#endif + + if (strcmp(name, "ntfs.streams.list")) + return -EOPNOTSUPP; +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + /* parent directory must be executable */ + if (ntfs_fuse_fill_security_context(&security) + && !ntfs_allowed_dir_access(&security,path,(ntfs_inode*)NULL, + (ntfs_inode*)NULL,S_IEXEC)) { + return (-errno); + } +#endif + ni = ntfs_pathname_to_inode(ctx->vol, NULL, path); + if (!ni) + return -errno; +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + if (!ntfs_allowed_access(&security,ni,S_IREAD)) { + ret = -errno; + goto exit; + } +#endif + actx = ntfs_attr_get_search_ctx(ni, NULL); + if (!actx) { + ret = -errno; + goto exit; + } + while (!ntfs_attr_lookup(AT_DATA, NULL, 0, CASE_SENSITIVE, + 0, NULL, 0, actx)) { + char *tmp_name = NULL; + int tmp_name_len; + + if (!actx->attr->name_length) + continue; + tmp_name_len = ntfs_ucstombs((ntfschar *)((u8*)actx->attr + + le16_to_cpu(actx->attr->name_offset)), + actx->attr->name_length, &tmp_name, 0); + if (tmp_name_len < 0) { + ret = -errno; + goto exit; + } + if (ret) + ret++; /* For space delimiter. */ + ret += tmp_name_len; + if (size) { + if ((size_t)ret <= size) { + /* Don't add space to the beginning of line. */ + if (to != value) { + *to = '\0'; + to++; + } + strncpy(to, tmp_name, tmp_name_len); + to += tmp_name_len; + } else { + free(tmp_name); + ret = -ERANGE; + goto exit; + } + } + free(tmp_name); + } + if (errno != ENOENT) + ret = -errno; +exit: + if (actx) + ntfs_attr_put_search_ctx(actx); + if (ntfs_inode_close(ni)) + set_fuse_error(&ret); + return ret; +} + +static __inline__ int ntfs_system_getxattr(struct SECURITY_CONTEXT *scx, + const char *path, int attr, ntfs_inode *ni, + char *value, size_t size) +{ + int res; + ntfs_inode *dir_ni; + char *dirpath; + char *p; + /* + * the returned value is the needed + * size. If it is too small, no copy + * is done, and the caller has to + * issue a new call with correct size. + */ + switch (attr) { + case XATTR_NTFS_ACL : + res = ntfs_get_ntfs_acl(scx, ni, value, size); + break; +#if POSIXACLS + case XATTR_POSIX_ACC : + res = ntfs_get_posix_acl(scx, ni, nf_ns_xattr_posix_access, + value, size); + break; + case XATTR_POSIX_DEF : + res = ntfs_get_posix_acl(scx, ni, nf_ns_xattr_posix_default, + value, size); + break; +#endif + case XATTR_NTFS_ATTRIB : + res = ntfs_get_ntfs_attrib(ni, value, size); + break; + case XATTR_NTFS_EFSINFO : + if (ctx->efs_raw) + res = ntfs_get_efs_info(ni, value, size); + else + res = -EPERM; + break; + case XATTR_NTFS_REPARSE_DATA : + res = ntfs_get_ntfs_reparse_data(ni, value, size); + break; + case XATTR_NTFS_OBJECT_ID : + res = ntfs_get_ntfs_object_id(ni, value, size); + break; + case XATTR_NTFS_DOS_NAME: + res = 0; + dirpath = strdup(path); + if (dirpath) { + p = strrchr(dirpath,'/'); /* always present */ + *p = 0; + dir_ni = ntfs_pathname_to_inode(ni->vol, + NULL, dirpath); + if (dir_ni) { + res = ntfs_get_ntfs_dos_name(ni, + dir_ni, value, size); + if (ntfs_inode_close(dir_ni)) + set_fuse_error(&res); + } else + res = -errno; + free(dirpath); + } else + res = -ENOMEM; + if (res < 0) + errno = -res; + break; + case XATTR_NTFS_TIMES: + res = ntfs_inode_get_times(ni, value, size); + break; + default : + /* + * make sure applications do not see + * Posix ACL not consistent with mode + */ + errno = EOPNOTSUPP; + res = -errno; + break; + } + return (res); +} + + +static int ntfs_fuse_getxattr(const char *path, const char *name, + char *value, size_t size) +{ + ntfs_inode *ni; + ntfs_attr *na = NULL; + ntfschar *lename = NULL; + int res, lename_len; + s64 rsize; + int attr; + int namespace; + struct SECURITY_CONTEXT security; + + attr = mapped_xattr_system(name); + if (attr != XATTR_UNMAPPED) { +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + /* + * hijack internal data and ACL retrieval, whatever + * mode was selected for xattr (from the user's + * point of view, ACLs are not xattr) + */ + ni = ntfs_check_access_xattr(&security, path, attr, FALSE); + if (ni) { + if (ntfs_allowed_access(&security,ni,S_IREAD)) { + res = ntfs_system_getxattr(&security, + path, attr, ni, value, size); + } else { + res = -errno; + } + if (ntfs_inode_close(ni)) + set_fuse_error(&res); + } else + res = -errno; +#else + /* + * Only hijack NTFS ACL retrieval if POSIX ACLS + * option is not selected + * Access control is done by fuse + */ + if (ntfs_fuse_is_named_data_stream(path)) + res = -EINVAL; /* n/a for named data streams. */ + else { + ni = ntfs_pathname_to_inode(ctx->vol, NULL, path); + if (ni) { + /* user mapping not mandatory */ + ntfs_fuse_fill_security_context(&security); + res = ntfs_system_getxattr(&security, + path, attr, ni, value, size); + if (ntfs_inode_close(ni)) + set_fuse_error(&res); + } else + res = -errno; + } +#endif + return (res); + } + if (ctx->streams == NF_STREAMS_INTERFACE_WINDOWS) + return ntfs_fuse_getxattr_windows(path, name, value, size); + if (ctx->streams == NF_STREAMS_INTERFACE_NONE) + return -EOPNOTSUPP; + namespace = xattr_namespace(name); + if (namespace == XATTRNS_NONE) + return -EOPNOTSUPP; +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + /* parent directory must be executable */ + if (ntfs_fuse_fill_security_context(&security) + && !ntfs_allowed_dir_access(&security,path,(ntfs_inode*)NULL, + (ntfs_inode*)NULL,S_IEXEC)) { + return (-errno); + } + /* trusted only readable by root */ + if ((namespace == XATTRNS_TRUSTED) + && security.uid) + return -EPERM; +#endif + ni = ntfs_pathname_to_inode(ctx->vol, NULL, path); + if (!ni) + return -errno; +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + /* file must be readable */ + if (!ntfs_allowed_access(&security, ni, S_IREAD)) { + res = -errno; + goto exit; + } +#endif + lename_len = fix_xattr_prefix(name, namespace, &lename); + if (lename_len == -1) { + res = -errno; + goto exit; + } + na = ntfs_attr_open(ni, AT_DATA, lename, lename_len); + if (!na) { + res = -ENODATA; + goto exit; + } + rsize = na->data_size; + if (ctx->efs_raw && + (na->data_flags & ATTR_IS_ENCRYPTED) && + NAttrNonResident(na)) + rsize = ((na->data_size + 511) & ~511)+2; + if (size) { + if (size >= (size_t)rsize) { + res = ntfs_attr_pread(na, 0, rsize, value); + if (res != rsize) + res = -errno; + } else + res = -ERANGE; + } else + res = rsize; +exit: + if (na) + ntfs_attr_close(na); + free(lename); + if (ntfs_inode_close(ni)) + set_fuse_error(&res); + return res; +} + +static __inline__ int ntfs_system_setxattr(struct SECURITY_CONTEXT *scx, + const char *path, int attr, ntfs_inode *ni, + const char *value, size_t size, int flags) +{ + int res; + char *dirpath; + char *p; + ntfs_inode *dir_ni; + + switch (attr) { + case XATTR_NTFS_ACL : + res = ntfs_set_ntfs_acl(scx, ni, value, size, flags); + break; +#if POSIXACLS + case XATTR_POSIX_ACC : + res = ntfs_set_posix_acl(scx,ni, nf_ns_xattr_posix_access, + value, size, flags); + break; + case XATTR_POSIX_DEF : + res = ntfs_set_posix_acl(scx, ni, nf_ns_xattr_posix_default, + value, size, flags); + break; +#endif + case XATTR_NTFS_ATTRIB : + res = ntfs_set_ntfs_attrib(ni, value, size, flags); + break; + case XATTR_NTFS_EFSINFO : + if (ctx->efs_raw) + res = ntfs_set_efs_info(ni, value, size, flags); + else + res = -EPERM; + break; + case XATTR_NTFS_REPARSE_DATA : + res = ntfs_set_ntfs_reparse_data(ni, value, size, flags); + break; + case XATTR_NTFS_OBJECT_ID : + res = ntfs_set_ntfs_object_id(ni, value, size, flags); + break; + case XATTR_NTFS_DOS_NAME: + res = 0; + dirpath = strdup(path); + if (dirpath) { + p = strrchr(dirpath,'/'); /* always present */ + *p = 0; + dir_ni = ntfs_pathname_to_inode(ni->vol, + NULL, dirpath); + if (dir_ni) + /* warning : this closes both inodes */ + res = ntfs_set_ntfs_dos_name(ni, dir_ni, + value,size,flags); + else + res = -errno; + free(dirpath); + } else + res = -ENOMEM; + if (res < 0) + errno = -res; + break; + case XATTR_NTFS_TIMES: + res = ntfs_inode_set_times(ni, value, size, flags); + break; + default : + /* + * make sure applications do not see + * Posix ACL not consistent with mode + */ + errno = EOPNOTSUPP; + res = -errno; + break; + } + return (res); +} + + +static int ntfs_fuse_setxattr(const char *path, const char *name, + const char *value, size_t size, int flags) +{ + ntfs_inode *ni; + ntfs_attr *na = NULL; + ntfschar *lename = NULL; + int res, lename_len; + size_t part, total; + int attr; + int namespace; + struct SECURITY_CONTEXT security; + + attr = mapped_xattr_system(name); + if (attr != XATTR_UNMAPPED) { +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + /* + * hijack internal data and ACL setting, whatever + * mode was selected for xattr (from the user's + * point of view, ACLs are not xattr) + * Note : updating an ACL does not set ctime + */ + ni = ntfs_check_access_xattr(&security,path,attr,TRUE); + if (ni) { + if (ntfs_allowed_as_owner(&security,ni)) { + res = ntfs_system_setxattr(&security, + path, attr, ni, value, size, flags); + if (res) + res = -errno; + } else + res = -errno; + if ((attr != XATTR_NTFS_DOS_NAME) + && ntfs_inode_close(ni)) + set_fuse_error(&res); + } else + res = -errno; +#else + /* + * Only hijack NTFS ACL setting if POSIX ACLS + * option is not selected + * Access control is partially done by fuse + */ + if (ntfs_fuse_is_named_data_stream(path)) + res = -EINVAL; /* n/a for named data streams. */ + else { + /* creation of a new name is not controlled by fuse */ + if (attr == XATTR_NTFS_DOS_NAME) + ni = ntfs_check_access_xattr(&security,path,attr,TRUE); + else + ni = ntfs_pathname_to_inode(ctx->vol, NULL, path); + if (ni) { + /* + * user mapping is not mandatory + * if defined, only owner is allowed + */ + if (!ntfs_fuse_fill_security_context(&security) + || ntfs_allowed_as_owner(&security,ni)) { + res = ntfs_system_setxattr(&security, + path, attr, ni, value, + size, flags); + if (res) + res = -errno; + } else + res = -errno; + if ((attr != XATTR_NTFS_DOS_NAME) + && ntfs_inode_close(ni)) + set_fuse_error(&res); + } else + res = -errno; + } +#endif + return (res); + } + if ((ctx->streams != NF_STREAMS_INTERFACE_XATTR) + && (ctx->streams != NF_STREAMS_INTERFACE_OPENXATTR)) + return -EOPNOTSUPP; + namespace = xattr_namespace(name); + if (namespace == XATTRNS_NONE) + return -EOPNOTSUPP; +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + /* parent directory must be executable */ + if (ntfs_fuse_fill_security_context(&security) + && !ntfs_allowed_dir_access(&security,path,(ntfs_inode*)NULL, + (ntfs_inode*)NULL,S_IEXEC)) { + return (-errno); + } + /* security and trusted only settable by root */ + if (((namespace == XATTRNS_SECURITY) + || (namespace == XATTRNS_TRUSTED)) + && security.uid) + return -EPERM; +#endif + ni = ntfs_pathname_to_inode(ctx->vol, NULL, path); + if (!ni) + return -errno; +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + switch (namespace) { + case XATTRNS_SECURITY : + case XATTRNS_TRUSTED : + if (security.uid) { + res = -EPERM; + goto exit; + } + break; + case XATTRNS_SYSTEM : + if (!ntfs_allowed_as_owner(&security,ni)) { + res = -EACCES; + goto exit; + } + break; + default : + if (!ntfs_allowed_access(&security,ni,S_IWRITE)) { + res = -EACCES; + goto exit; + } + break; + } +#endif + lename_len = fix_xattr_prefix(name, namespace, &lename); + if (lename_len == -1) { + res = -errno; + goto exit; + } + na = ntfs_attr_open(ni, AT_DATA, lename, lename_len); + if (na && flags == XATTR_CREATE) { + res = -EEXIST; + goto exit; + } + if (!na) { + if (flags == XATTR_REPLACE) { + res = -ENODATA; + goto exit; + } + if (ntfs_attr_add(ni, AT_DATA, lename, lename_len, NULL, 0)) { + res = -errno; + goto exit; + } + if (!(ni->flags & FILE_ATTR_ARCHIVE)) { + set_archive(ni); + NInoFileNameSetDirty(ni); + } + na = ntfs_attr_open(ni, AT_DATA, lename, lename_len); + if (!na) { + res = -errno; + goto exit; + } + } else { + /* currently compressed streams can only be wiped out */ + if (ntfs_attr_truncate(na, (s64)0 /* size */)) { + res = -errno; + goto exit; + } + } + total = 0; + if (size) { + do { + part = ntfs_attr_pwrite(na, total, size - total, + &value[total]); + if (part > 0) + total += part; + } while ((part > 0) && (total < size)); + if (total != size) + res = -errno; + else + if (!(res = ntfs_attr_pclose(na))) + if (ctx->efs_raw + && (ni->flags & FILE_ATTR_ENCRYPTED)) + res = ntfs_efs_fixup_attribute(NULL, + na); + if (total && !(ni->flags & FILE_ATTR_ARCHIVE)) { + set_archive(ni); + NInoFileNameSetDirty(ni); + } + } else + res = 0; +exit: + if (na) + ntfs_attr_close(na); + free(lename); + if (ntfs_inode_close(ni)) + set_fuse_error(&res); + return res; +} + +static __inline__ int ntfs_system_removexattr(const char *path, + int attr) +{ + int res; + ntfs_inode *dir_ni; + ntfs_inode *ni; + char *dirpath; + char *p; + struct SECURITY_CONTEXT security; + + res = 0; + switch (attr) { + /* + * Removal of NTFS ACL, ATTRIB, EFSINFO or TIMES + * is never allowed + */ + case XATTR_NTFS_ACL : + case XATTR_NTFS_ATTRIB : + case XATTR_NTFS_EFSINFO : + case XATTR_NTFS_TIMES : + res = -EPERM; + break; +#if POSIXACLS + case XATTR_POSIX_ACC : + case XATTR_POSIX_DEF : + ni = ntfs_check_access_xattr(&security, path, attr, TRUE); + if (ni) { + if (!ntfs_allowed_as_owner(&security,ni) + || ntfs_remove_posix_acl(&security,ni, + (attr == XATTR_POSIX_ACC ? + nf_ns_xattr_posix_access : + nf_ns_xattr_posix_default))) + res = -errno; + if (ntfs_inode_close(ni)) + set_fuse_error(&res); + } else + res = -errno; + break; +#endif + case XATTR_NTFS_REPARSE_DATA : + ni = ntfs_check_access_xattr(&security, path, attr, TRUE); + if (ni) { + if (!ntfs_allowed_as_owner(&security,ni) + || ntfs_remove_ntfs_reparse_data(ni)) + res = -errno; + if (ntfs_inode_close(ni)) + set_fuse_error(&res); + } else + res = -errno; + break; + case XATTR_NTFS_OBJECT_ID : + ni = ntfs_check_access_xattr(&security,path,attr,TRUE); + if (ni) { + if (!ntfs_allowed_as_owner(&security,ni) + || ntfs_remove_ntfs_object_id(ni)) + res = -errno; + if (ntfs_inode_close(ni)) + set_fuse_error(&res); + } else + res = -errno; + break; + case XATTR_NTFS_DOS_NAME: + res = 0; + ni = ntfs_check_access_xattr(&security,path,attr,TRUE); + if (ni) { + dirpath = strdup(path); + if (dirpath) { + p = strrchr(dirpath,'/'); /* always present */ + *p = 0; + dir_ni = ntfs_pathname_to_inode(ni->vol, + NULL, dirpath); + if (!dir_ni + || ntfs_remove_ntfs_dos_name(ni, dir_ni)) + res = -errno; + free(dirpath); + } else + res = -ENOMEM; + if (res < 0) + errno = -res; + } else + res = -errno; + break; + default : + /* + * make sure applications do not see + * Posix ACL not consistent with mode + */ + errno = EOPNOTSUPP; + res = -errno; + break; + } + return (res); +} + +static int ntfs_fuse_removexattr(const char *path, const char *name) +{ + ntfs_inode *ni; + ntfschar *lename = NULL; + int res = 0, lename_len; + int attr; + int namespace; +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + struct SECURITY_CONTEXT security; +#endif + + attr = mapped_xattr_system(name); + if (attr != XATTR_UNMAPPED) { +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + + /* + * hijack internal data and ACL removal, whatever + * mode was selected for xattr (from the user's + * point of view, ACLs are not xattr) + * Note : updating an ACL does not set ctime + */ + res = ntfs_system_removexattr(path, attr); +#else + /* + * Only hijack NTFS ACL and ATTRIB removal if POSIX ACLS + * option is not selected + * Access control is partially done by fuse + */ + if (ntfs_fuse_is_named_data_stream(path)) + res = -EINVAL; /* n/a for named data streams. */ + else { + res = ntfs_system_removexattr(path, attr); + } +#endif + return (res); + } + if ((ctx->streams != NF_STREAMS_INTERFACE_XATTR) + && (ctx->streams != NF_STREAMS_INTERFACE_OPENXATTR)) + return -EOPNOTSUPP; + namespace = xattr_namespace(name); + if (namespace == XATTRNS_NONE) + return -EOPNOTSUPP; +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + /* parent directory must be executable */ + if (ntfs_fuse_fill_security_context(&security) + && !ntfs_allowed_dir_access(&security,path,(ntfs_inode*)NULL, + (ntfs_inode*)NULL,S_IEXEC)) { + return (-errno); + } + /* security and trusted only settable by root */ + if (((namespace == XATTRNS_SECURITY) + || (namespace == XATTRNS_TRUSTED)) + && security.uid) + return -EACCES; +#endif + ni = ntfs_pathname_to_inode(ctx->vol, NULL, path); + if (!ni) + return -errno; +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + switch (namespace) { + case XATTRNS_SECURITY : + case XATTRNS_TRUSTED : + if (security.uid) { + res = -EPERM; + goto exit; + } + break; + case XATTRNS_SYSTEM : + if (!ntfs_allowed_as_owner(&security,ni)) { + res = -EACCES; + goto exit; + } + break; + default : + if (!ntfs_allowed_access(&security,ni,S_IWRITE)) { + res = -EACCES; + goto exit; + } + break; + } +#endif + lename_len = fix_xattr_prefix(name, namespace, &lename); + if (lename_len == -1) { + res = -errno; + goto exit; + } + if (ntfs_attr_remove(ni, AT_DATA, lename, lename_len)) { + if (errno == ENOENT) + errno = ENODATA; + res = -errno; + } + if (!(ni->flags & FILE_ATTR_ARCHIVE)) { + set_archive(ni); + NInoFileNameSetDirty(ni); + } +exit: + free(lename); + if (ntfs_inode_close(ni)) + set_fuse_error(&res); + return res; +} + +#else +#if POSIXACLS +#error "Option inconsistency : POSIXACLS requires SETXATTR" +#endif +#endif /* HAVE_SETXATTR */ + +static void ntfs_close(void) +{ + struct SECURITY_CONTEXT security; + + if (!ctx) + return; + + if (!ctx->vol) + return; + + if (ctx->mounted) { + ntfs_log_info("Unmounting %s (%s)\n", opts.device, + ctx->vol->vol_name); + if (ntfs_fuse_fill_security_context(&security)) { + if (ctx->seccache && ctx->seccache->head.p_reads) { + ntfs_log_info("Permissions cache : %lu writes, " + "%lu reads, %lu.%1lu%% hits\n", + ctx->seccache->head.p_writes, + ctx->seccache->head.p_reads, + 100 * ctx->seccache->head.p_hits + / ctx->seccache->head.p_reads, + 1000 * ctx->seccache->head.p_hits + / ctx->seccache->head.p_reads % 10); + } + } + ntfs_close_secure(&security); + } + + if (ntfs_umount(ctx->vol, FALSE)) + ntfs_log_perror("Failed to close volume %s", opts.device); + + ctx->vol = NULL; +} + +static void ntfs_fuse_destroy2(void *unused __attribute__((unused))) +{ + ntfs_close(); +} + +static struct fuse_operations ntfs_3g_ops = { +#if defined(HAVE_UTIMENSAT) && (defined(FUSE_INTERNAL) || (FUSE_VERSION > 28)) + /* + * Accept UTIME_NOW and UTIME_OMIT in utimens, when + * using internal fuse or a fuse version since 2.9 + * (this field is not present in older versions) + */ + .flag_utime_omit_ok = 1, +#endif + .getattr = ntfs_fuse_getattr, + .readlink = ntfs_fuse_readlink, + .readdir = ntfs_fuse_readdir, + .open = ntfs_fuse_open, + .release = ntfs_fuse_release, + .read = ntfs_fuse_read, + .write = ntfs_fuse_write, + .truncate = ntfs_fuse_truncate, + .ftruncate = ntfs_fuse_ftruncate, +#if HAVE_SYS_STATVFS_H + .statfs = ntfs_fuse_statfs, +#endif + .chmod = ntfs_fuse_chmod, + .chown = ntfs_fuse_chown, + .create = ntfs_fuse_create_file, + .mknod = ntfs_fuse_mknod, + .symlink = ntfs_fuse_symlink, + .link = ntfs_fuse_link, + .unlink = ntfs_fuse_unlink, + .rename = ntfs_fuse_rename, + .mkdir = ntfs_fuse_mkdir, + .rmdir = ntfs_fuse_rmdir, +#ifdef HAVE_UTIMENSAT + .utimens = ntfs_fuse_utimens, +#else + .utime = ntfs_fuse_utime, +#endif + .bmap = ntfs_fuse_bmap, + .destroy = ntfs_fuse_destroy2, +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + .access = ntfs_fuse_access, + .opendir = ntfs_fuse_opendir, +#endif +#ifdef HAVE_SETXATTR + .getxattr = ntfs_fuse_getxattr, + .setxattr = ntfs_fuse_setxattr, + .removexattr = ntfs_fuse_removexattr, + .listxattr = ntfs_fuse_listxattr, +#endif /* HAVE_SETXATTR */ +#if defined(__APPLE__) || defined(__DARWIN__) + /* MacFUSE extensions. */ + .getxtimes = ntfs_macfuse_getxtimes, + .setcrtime = ntfs_macfuse_setcrtime, + .setbkuptime = ntfs_macfuse_setbkuptime, + .setchgtime = ntfs_macfuse_setchgtime, +#endif /* defined(__APPLE__) || defined(__DARWIN__) */ +#if defined(FUSE_CAP_DONT_MASK) || (defined(__APPLE__) || defined(__DARWIN__)) + .init = ntfs_init +#endif +}; + +static int ntfs_fuse_init(void) +{ + ctx = ntfs_calloc(sizeof(ntfs_fuse_context_t)); + if (!ctx) + return -1; + + *ctx = (ntfs_fuse_context_t) { + .uid = getuid(), + .gid = getgid(), +#if defined(linux) + .streams = NF_STREAMS_INTERFACE_XATTR, +#else + .streams = NF_STREAMS_INTERFACE_NONE, +#endif + .atime = ATIME_RELATIVE, + .silent = TRUE, + .recover = TRUE + }; + return 0; +} + +static int ntfs_open(const char *device) +{ + unsigned long flags = 0; + + if (!ctx->blkdev) + flags |= MS_EXCLUSIVE; + if (ctx->ro) + flags |= MS_RDONLY; + if (ctx->recover) + flags |= MS_RECOVER; + if (ctx->hiberfile) + flags |= MS_IGNORE_HIBERFILE; + + ctx->vol = ntfs_mount(device, flags); + if (!ctx->vol) { + ntfs_log_perror("Failed to mount '%s'", device); + goto err_out; + } + + ctx->vol->free_clusters = ntfs_attr_get_free_bits(ctx->vol->lcnbmp_na); + if (ctx->vol->free_clusters < 0) { + ntfs_log_perror("Failed to read NTFS $Bitmap"); + goto err_out; + } + + ctx->vol->free_mft_records = ntfs_get_nr_free_mft_records(ctx->vol); + if (ctx->vol->free_mft_records < 0) { + ntfs_log_perror("Failed to calculate free MFT records"); + goto err_out; + } + + if (ctx->hiberfile && ntfs_volume_check_hiberfile(ctx->vol, 0)) { + if (errno != EPERM) + goto err_out; + if (ntfs_fuse_rm("/hiberfil.sys")) + goto err_out; + } + + errno = 0; +err_out: + return ntfs_volume_error(errno); + +} + +#define STRAPPEND_MAX_INSIZE 8192 +#define strappend_is_large(x) ((x) > STRAPPEND_MAX_INSIZE) + +static int strappend(char **dest, const char *append) +{ + char *p; + size_t size_append, size_dest = 0; + + if (!dest) + return -1; + if (!append) + return 0; + + size_append = strlen(append); + if (*dest) + size_dest = strlen(*dest); + + if (strappend_is_large(size_dest) || strappend_is_large(size_append)) { + errno = EOVERFLOW; + ntfs_log_perror("%s: Too large input buffer", EXEC_NAME); + return -1; + } + + p = realloc(*dest, size_dest + size_append + 1); + if (!p) { + ntfs_log_perror("%s: Memory realloction failed", EXEC_NAME); + return -1; + } + + *dest = p; + strcpy(*dest + size_dest, append); + + return 0; +} + +static int bogus_option_value(char *val, const char *s) +{ + if (val) { + ntfs_log_error("'%s' option shouldn't have value.\n", s); + return -1; + } + return 0; +} + +static int missing_option_value(char *val, const char *s) +{ + if (!val) { + ntfs_log_error("'%s' option should have a value.\n", s); + return -1; + } + return 0; +} + +static char *parse_mount_options(const char *orig_opts) +{ + char *options, *s, *opt, *val, *ret = NULL; + BOOL no_def_opts = FALSE; + int default_permissions = 0; + int want_permissions = 0; + + ctx->secure_flags = 0; +#ifdef HAVE_SETXATTR /* extended attributes interface required */ + ctx->efs_raw = FALSE; +#endif /* HAVE_SETXATTR */ + options = strdup(orig_opts ? orig_opts : ""); + if (!options) { + ntfs_log_perror("%s: strdup failed", EXEC_NAME); + return NULL; + } + + s = options; + while (s && *s && (val = strsep(&s, ","))) { + opt = strsep(&val, "="); + if (!strcmp(opt, "ro")) { /* Read-only mount. */ + if (bogus_option_value(val, "ro")) + goto err_exit; + ctx->ro = TRUE; + if (strappend(&ret, "ro,")) + goto err_exit; + } else if (!strcmp(opt, "noatime")) { + if (bogus_option_value(val, "noatime")) + goto err_exit; + ctx->atime = ATIME_DISABLED; + } else if (!strcmp(opt, "atime")) { + if (bogus_option_value(val, "atime")) + goto err_exit; + ctx->atime = ATIME_ENABLED; + } else if (!strcmp(opt, "relatime")) { + if (bogus_option_value(val, "relatime")) + goto err_exit; + ctx->atime = ATIME_RELATIVE; + } else if (!strcmp(opt, "fake_rw")) { + if (bogus_option_value(val, "fake_rw")) + goto err_exit; + ctx->ro = TRUE; + } else if (!strcmp(opt, "fsname")) { /* Filesystem name. */ + /* + * We need this to be able to check whether filesystem + * mounted or not. + */ + ntfs_log_error("'fsname' is unsupported option.\n"); + goto err_exit; + } else if (!strcmp(opt, "no_def_opts")) { + if (bogus_option_value(val, "no_def_opts")) + goto err_exit; + no_def_opts = TRUE; /* Don't add default options. */ + } else if (!strcmp(opt, "default_permissions")) { + default_permissions = 1; + } else if (!strcmp(opt, "umask")) { + if (missing_option_value(val, "umask")) + goto err_exit; + sscanf(val, "%o", &ctx->fmask); + ctx->dmask = ctx->fmask; + want_permissions = 1; + } else if (!strcmp(opt, "fmask")) { + if (missing_option_value(val, "fmask")) + goto err_exit; + sscanf(val, "%o", &ctx->fmask); + want_permissions = 1; + } else if (!strcmp(opt, "dmask")) { + if (missing_option_value(val, "dmask")) + goto err_exit; + sscanf(val, "%o", &ctx->dmask); + want_permissions = 1; + } else if (!strcmp(opt, "uid")) { + if (missing_option_value(val, "uid")) + goto err_exit; + sscanf(val, "%i", &ctx->uid); + want_permissions = 1; + } else if (!strcmp(opt, "gid")) { + if (missing_option_value(val, "gid")) + goto err_exit; + sscanf(val, "%i", &ctx->gid); + want_permissions = 1; + } else if (!strcmp(opt, "show_sys_files")) { + if (bogus_option_value(val, "show_sys_files")) + goto err_exit; + ctx->show_sys_files = TRUE; + } else if (!strcmp(opt, "silent")) { + if (bogus_option_value(val, "silent")) + goto err_exit; + ctx->silent = TRUE; + } else if (!strcmp(opt, "recover")) { + if (bogus_option_value(val, "recover")) + goto err_exit; + ctx->recover = TRUE; + } else if (!strcmp(opt, "norecover")) { + if (bogus_option_value(val, "norecover")) + goto err_exit; + ctx->recover = FALSE; + } else if (!strcmp(opt, "remove_hiberfile")) { + if (bogus_option_value(val, "remove_hiberfile")) + goto err_exit; + ctx->hiberfile = TRUE; + } else if (!strcmp(opt, "locale")) { + if (missing_option_value(val, "locale")) + goto err_exit; + ntfs_set_char_encoding(val); +#if defined(__APPLE__) || defined(__DARWIN__) +#ifdef ENABLE_NFCONV + } else if (!strcmp(opt, "nfconv")) { + if (bogus_option_value(val, "nfconv")) + goto err_exit; + if (ntfs_macosx_normalize_filenames(1)) { + ntfs_log_error("ntfs_macosx_normalize_filenames(1) failed!\n"); + goto err_exit; + } + } else if (!strcmp(opt, "nonfconv")) { + if (bogus_option_value(val, "nonfconv")) + goto err_exit; + if (ntfs_macosx_normalize_filenames(0)) { + ntfs_log_error("ntfs_macosx_normalize_filenames(0) failed!\n"); + goto err_exit; + } +#endif /* ENABLE_NFCONV */ +#endif /* defined(__APPLE__) || defined(__DARWIN__) */ + } else if (!strcmp(opt, "streams_interface")) { + if (missing_option_value(val, "streams_interface")) + goto err_exit; + if (!strcmp(val, "none")) + ctx->streams = NF_STREAMS_INTERFACE_NONE; + else if (!strcmp(val, "xattr")) + ctx->streams = NF_STREAMS_INTERFACE_XATTR; + else if (!strcmp(val, "openxattr")) + ctx->streams = NF_STREAMS_INTERFACE_OPENXATTR; + else if (!strcmp(val, "windows")) + ctx->streams = NF_STREAMS_INTERFACE_WINDOWS; + else { + ntfs_log_error("Invalid named data streams " + "access interface.\n"); + goto err_exit; + } + } else if (!strcmp(opt, "user_xattr")) { + ctx->streams = NF_STREAMS_INTERFACE_XATTR; + } else if (!strcmp(opt, "noauto")) { + /* Don't pass noauto option to fuse. */ + } else if (!strcmp(opt, "debug")) { + if (bogus_option_value(val, "debug")) + goto err_exit; + ctx->debug = TRUE; + ntfs_log_set_levels(NTFS_LOG_LEVEL_DEBUG); + ntfs_log_set_levels(NTFS_LOG_LEVEL_TRACE); + } else if (!strcmp(opt, "no_detach")) { + if (bogus_option_value(val, "no_detach")) + goto err_exit; + ctx->no_detach = TRUE; + } else if (!strcmp(opt, "remount")) { + ntfs_log_error("Remounting is not supported at present." + " You have to umount volume and then " + "mount it once again.\n"); + goto err_exit; + } else if (!strcmp(opt, "blksize")) { + ntfs_log_info("WARNING: blksize option is ignored " + "because ntfs-3g must calculate it.\n"); + } else if (!strcmp(opt, "inherit")) { + /* + * JPA do not overwrite inherited permissions + * in create() + */ + ctx->inherit = TRUE; + } else if (!strcmp(opt, "addsecurids")) { + /* + * JPA create security ids for files being read + * with an individual security attribute + */ + ctx->secure_flags |= (1 << SECURITY_ADDSECURIDS); + } else if (!strcmp(opt, "staticgrps")) { + /* + * JPA use static definition of groups + * for file access control + */ + ctx->secure_flags |= (1 << SECURITY_STATICGRPS); + } else if (!strcmp(opt, "usermapping")) { + if (!val) { + ntfs_log_error("'usermapping' option should have " + "a value.\n"); + goto err_exit; + } + ctx->usermap_path = strdup(val); + if (!ctx->usermap_path) { + ntfs_log_error("no more memory to store " + "'usermapping' option.\n"); + goto err_exit; + } +#ifdef HAVE_SETXATTR /* extended attributes interface required */ + } else if (!strcmp(opt, "efs_raw")) { + if (bogus_option_value(val, "efs_raw")) + goto err_exit; + ctx->efs_raw = TRUE; +#endif /* HAVE_SETXATTR */ + } else { /* Probably FUSE option. */ + if (strappend(&ret, opt)) + goto err_exit; + if (val) { + if (strappend(&ret, "=")) + goto err_exit; + if (strappend(&ret, val)) + goto err_exit; + } + if (strappend(&ret, ",")) + goto err_exit; + } + } + if (!no_def_opts && strappend(&ret, def_opts)) + goto err_exit; + if (default_permissions && strappend(&ret, "default_permissions,")) + goto err_exit; + + if (ctx->atime == ATIME_RELATIVE && strappend(&ret, "relatime,")) + goto err_exit; + else if (ctx->atime == ATIME_ENABLED && strappend(&ret, "atime,")) + goto err_exit; + else if (ctx->atime == ATIME_DISABLED && strappend(&ret, "noatime,")) + goto err_exit; + + if (strappend(&ret, "fsname=")) + goto err_exit; + if (strappend(&ret, opts.device)) + goto err_exit; + if (default_permissions) + ctx->secure_flags |= (1 << SECURITY_DEFAULT); + if (want_permissions) + ctx->secure_flags |= (1 << SECURITY_WANTED); + if (ctx->ro) + ctx->secure_flags &= ~(1 << SECURITY_ADDSECURIDS); +exit: + free(options); + return ret; +err_exit: + free(ret); + ret = NULL; + goto exit; +} + +static void usage(void) +{ + ntfs_log_info(usage_msg, EXEC_NAME, VERSION, FUSE_TYPE, fuse_version(), + 4 + POSIXACLS*6 - KERNELPERMS*3 + CACHEING, + EXEC_NAME, ntfs_home); +} + +#ifndef HAVE_REALPATH +/* If there is no realpath() on the system, provide a dummy one. */ +static char *realpath(const char *path, char *resolved_path) +{ + strncpy(resolved_path, path, PATH_MAX); + resolved_path[PATH_MAX] = '\0'; + return resolved_path; +} +#endif + +/** + * parse_options - Read and validate the programs command line + * Read the command line, verify the syntax and parse the options. + * + * Return: 0 success, -1 error. + */ +static int parse_options(int argc, char *argv[]) +{ + int c; + + static const char *sopt = "-o:hvV"; + static const struct option lopt[] = { + { "options", required_argument, NULL, 'o' }, + { "help", no_argument, NULL, 'h' }, + { "verbose", no_argument, NULL, 'v' }, + { "version", no_argument, NULL, 'V' }, + { NULL, 0, NULL, 0 } + }; + + opterr = 0; /* We'll handle the errors, thank you. */ + + while ((c = getopt_long(argc, argv, sopt, lopt, NULL)) != -1) { + switch (c) { + case 1: /* A non-option argument */ + if (!opts.device) { + opts.device = ntfs_malloc(PATH_MAX + 1); + if (!opts.device) + return -1; + + /* Canonicalize device name (mtab, etc) */ + if (!realpath(optarg, opts.device)) { + ntfs_log_perror("%s: Failed to access " + "volume '%s'", EXEC_NAME, optarg); + free(opts.device); + opts.device = NULL; + return -1; + } + } else if (!opts.mnt_point) { + opts.mnt_point = optarg; + } else { + ntfs_log_error("%s: You must specify exactly one " + "device and exactly one mount " + "point.\n", EXEC_NAME); + return -1; + } + break; + case 'o': + if (opts.options) + if (strappend(&opts.options, ",")) + return -1; + if (strappend(&opts.options, optarg)) + return -1; + break; + case 'h': + usage(); + exit(9); + case 'v': + /* + * We must handle the 'verbose' option even if + * we don't use it because mount(8) passes it. + */ + break; + case 'V': + ntfs_log_info("%s %s %s %d\n", EXEC_NAME, VERSION, + FUSE_TYPE, fuse_version()); + exit(0); + default: + ntfs_log_error("%s: Unknown option '%s'.\n", EXEC_NAME, + argv[optind - 1]); + return -1; + } + } + + if (!opts.device) { + ntfs_log_error("%s: No device is specified.\n", EXEC_NAME); + return -1; + } + if (!opts.mnt_point) { + ntfs_log_error("%s: No mountpoint is specified.\n", EXEC_NAME); + return -1; + } + + return 0; +} + +#if defined(linux) || defined(__uClinux__) + +static const char *dev_fuse_msg = +"HINT: You should be root, or make ntfs-3g setuid root, or load the FUSE\n" +" kernel module as root ('modprobe fuse' or 'insmod /fuse.ko'" +" or insmod /fuse.o'). Make also sure that the fuse device" +" exists. It's usually either /dev/fuse or /dev/misc/fuse."; + +static const char *fuse26_kmod_msg = +"WARNING: Deficient Linux kernel detected. Some driver features are\n" +" not available (swap file on NTFS, boot from NTFS by LILO), and\n" +" unmount is not safe unless it's made sure the ntfs-3g process\n" +" naturally terminates after calling 'umount'. If you wish this\n" +" message to disappear then you should upgrade to at least kernel\n" +" version 2.6.20, or request help from your distribution to fix\n" +" the kernel problem. The below web page has more information:\n" +" http://ntfs-3g.org/support.html#fuse26\n" +"\n"; + +static void mknod_dev_fuse(const char *dev) +{ + struct stat st; + + if (stat(dev, &st) && (errno == ENOENT)) { + mode_t mask = umask(0); + if (mknod(dev, S_IFCHR | 0666, makedev(10, 229))) { + ntfs_log_perror("Failed to create '%s'", dev); + if (errno == EPERM) + ntfs_log_error("%s", dev_fuse_msg); + } + umask(mask); + } +} + +static void create_dev_fuse(void) +{ + mknod_dev_fuse("/dev/fuse"); + +#ifdef __UCLIBC__ + { + struct stat st; + /* The fuse device is under /dev/misc using devfs. */ + if (stat("/dev/misc", &st) && (errno == ENOENT)) { + mode_t mask = umask(0); + mkdir("/dev/misc", 0775); + umask(mask); + } + mknod_dev_fuse("/dev/misc/fuse"); + } +#endif +} + +static fuse_fstype get_fuse_fstype(void) +{ + char buf[256]; + fuse_fstype fstype = FSTYPE_NONE; + + FILE *f = fopen("/proc/filesystems", "r"); + if (!f) { + ntfs_log_perror("Failed to open /proc/filesystems"); + return FSTYPE_UNKNOWN; + } + + while (fgets(buf, sizeof(buf), f)) { + if (strstr(buf, "fuseblk\n")) { + fstype = FSTYPE_FUSEBLK; + break; + } + if (strstr(buf, "fuse\n")) + fstype = FSTYPE_FUSE; + } + + fclose(f); + return fstype; +} + +static fuse_fstype load_fuse_module(void) +{ + int i; + struct stat st; + pid_t pid; + const char *cmd = "/sbin/modprobe"; + struct timespec req = { 0, 100000000 }; /* 100 msec */ + fuse_fstype fstype; + + if (!stat(cmd, &st) && !geteuid()) { + pid = fork(); + if (!pid) { + execl(cmd, cmd, "fuse", NULL); + _exit(1); + } else if (pid != -1) + waitpid(pid, NULL, 0); + } + + for (i = 0; i < 10; i++) { + /* + * We sleep first because despite the detection of the loaded + * FUSE kernel module, fuse_mount() can still fail if it's not + * fully functional/initialized. Note, of course this is still + * unreliable but usually helps. + */ + nanosleep(&req, NULL); + fstype = get_fuse_fstype(); + if (fstype != FSTYPE_NONE) + break; + } + return fstype; +} + +#endif + +static struct fuse_chan *try_fuse_mount(char *parsed_options) +{ + struct fuse_chan *fc = NULL; + struct fuse_args margs = FUSE_ARGS_INIT(0, NULL); + + /* The fuse_mount() options get modified, so we always rebuild it */ + if ((fuse_opt_add_arg(&margs, EXEC_NAME) == -1 || + fuse_opt_add_arg(&margs, "-o") == -1 || + fuse_opt_add_arg(&margs, parsed_options) == -1)) { + ntfs_log_error("Failed to set FUSE options.\n"); + goto free_args; + } + + fc = fuse_mount(opts.mnt_point, &margs); +free_args: + fuse_opt_free_args(&margs); + return fc; + +} + +static int set_fuseblk_options(char **parsed_options) +{ + char options[64]; + long pagesize; + u32 blksize = ctx->vol->cluster_size; + + pagesize = sysconf(_SC_PAGESIZE); + if (pagesize < 1) + pagesize = 4096; + + if (blksize > (u32)pagesize) + blksize = pagesize; + + snprintf(options, sizeof(options), ",blkdev,blksize=%u", blksize); + if (strappend(parsed_options, options)) + return -1; + return 0; +} + +static struct fuse *mount_fuse(char *parsed_options) +{ + struct fuse *fh = NULL; + struct fuse_args args = FUSE_ARGS_INIT(0, NULL); + + ctx->fc = try_fuse_mount(parsed_options); + if (!ctx->fc) + return NULL; + + if (fuse_opt_add_arg(&args, "") == -1) + goto err; +#if !CACHEING + if (fuse_opt_add_arg(&args, "-ouse_ino,kernel_cache,attr_timeout=0") == -1) + goto err; +#else + if (fuse_opt_add_arg(&args, "-ouse_ino,kernel_cache,attr_timeout=1") == -1) + goto err; +#endif + if (ctx->debug) + if (fuse_opt_add_arg(&args, "-odebug") == -1) + goto err; + + fh = fuse_new(ctx->fc, &args , &ntfs_3g_ops, sizeof(ntfs_3g_ops), NULL); + if (!fh) + goto err; + + if (fuse_set_signal_handlers(fuse_get_session(fh))) + goto err_destory; +out: + fuse_opt_free_args(&args); + return fh; +err_destory: + fuse_destroy(fh); + fh = NULL; +err: + fuse_unmount(opts.mnt_point, ctx->fc); + goto out; +} + +static void setup_logging(char *parsed_options) +{ + if (!ctx->no_detach) { + if (daemon(0, ctx->debug)) + ntfs_log_error("Failed to daemonize.\n"); + else if (!ctx->debug) { +#ifndef DEBUG + ntfs_log_set_handler(ntfs_log_handler_syslog); + /* Override default libntfs identify. */ + openlog(EXEC_NAME, LOG_PID, LOG_DAEMON); +#endif + } + } + + ctx->seccache = (struct PERMISSIONS_CACHE*)NULL; + + ntfs_log_info("Version %s %s %d\n", VERSION, FUSE_TYPE, fuse_version()); + ntfs_log_info("Mounted %s (%s, label \"%s\", NTFS %d.%d)\n", + opts.device, (ctx->ro) ? "Read-Only" : "Read-Write", + ctx->vol->vol_name, ctx->vol->major_ver, + ctx->vol->minor_ver); + ntfs_log_info("Cmdline options: %s\n", opts.options ? opts.options : ""); + ntfs_log_info("Mount options: %s\n", parsed_options); +} + +int main(int argc, char *argv[]) +{ + char *parsed_options = NULL; + struct fuse *fh; +#if !(defined(__sun) && defined (__SVR4)) + fuse_fstype fstype = FSTYPE_UNKNOWN; +#endif + const char *permissions_mode = (const char*)NULL; + const char *failed_secure = (const char*)NULL; + struct stat sbuf; + int err, fd; + + /* + * Make sure file descriptors 0, 1 and 2 are open, + * otherwise chaos would ensue. + */ + do { + fd = open("/dev/null", O_RDWR); + if (fd > 2) + close(fd); + } while (fd >= 0 && fd <= 2); + +#ifndef FUSE_INTERNAL + if ((getuid() != geteuid()) || (getgid() != getegid())) { + fprintf(stderr, "%s", setuid_msg); + return NTFS_VOLUME_INSECURE; + } +#endif + if (drop_privs()) + return NTFS_VOLUME_NO_PRIVILEGE; + + ntfs_set_locale(); + ntfs_log_set_handler(ntfs_log_handler_stderr); + + if (parse_options(argc, argv)) { + usage(); + return NTFS_VOLUME_SYNTAX_ERROR; + } + + if (ntfs_fuse_init()) { + err = NTFS_VOLUME_OUT_OF_MEMORY; + goto err2; + } + + parsed_options = parse_mount_options(opts.options); + if (!parsed_options) { + err = NTFS_VOLUME_SYNTAX_ERROR; + goto err_out; + } + + /* need absolute mount point for junctions */ + if (opts.mnt_point[0] == '/') + ctx->abs_mnt_point = strdup(opts.mnt_point); + else { + ctx->abs_mnt_point = (char*)ntfs_malloc(PATH_MAX); + if (ctx->abs_mnt_point) { + if (getcwd(ctx->abs_mnt_point, + PATH_MAX - strlen(opts.mnt_point) - 1)) { + strcat(ctx->abs_mnt_point, "/"); + strcat(ctx->abs_mnt_point, opts.mnt_point); + } + } + } + if (!ctx->abs_mnt_point) { + err = NTFS_VOLUME_OUT_OF_MEMORY; + goto err_out; + } + + ctx->security.uid = 0; + ctx->security.gid = 0; + if ((opts.mnt_point[0] == '/') + && !stat(opts.mnt_point,&sbuf)) { + /* collect owner of mount point, useful for default mapping */ + ctx->security.uid = sbuf.st_uid; + ctx->security.gid = sbuf.st_gid; + } + +#if defined(linux) || defined(__uClinux__) + fstype = get_fuse_fstype(); + + err = NTFS_VOLUME_NO_PRIVILEGE; + if (restore_privs()) + goto err_out; + + if (fstype == FSTYPE_NONE || fstype == FSTYPE_UNKNOWN) + fstype = load_fuse_module(); + create_dev_fuse(); + + if (drop_privs()) + goto err_out; +#endif + if (stat(opts.device, &sbuf)) { + ntfs_log_perror("Failed to access '%s'", opts.device); + err = NTFS_VOLUME_NO_PRIVILEGE; + goto err_out; + } + +#if !(defined(__sun) && defined (__SVR4)) + /* Always use fuseblk for block devices unless it's surely missing. */ + if (S_ISBLK(sbuf.st_mode) && (fstype != FSTYPE_FUSE)) + ctx->blkdev = TRUE; +#endif + +#ifndef FUSE_INTERNAL + if (getuid() && ctx->blkdev) { + ntfs_log_error("%s", unpriv_fuseblk_msg); + err = NTFS_VOLUME_NO_PRIVILEGE; + goto err2; + } +#endif + err = ntfs_open(opts.device); + if (err) + goto err_out; + + /* We must do this after ntfs_open() to be able to set the blksize */ + if (ctx->blkdev && set_fuseblk_options(&parsed_options)) + goto err_out; + + ctx->security.vol = ctx->vol; + ctx->vol->secure_flags = ctx->secure_flags; +#ifdef HAVE_SETXATTR /* extended attributes interface required */ + ctx->vol->efs_raw = ctx->efs_raw; +#endif /* HAVE_SETXATTR */ + /* JPA open $Secure, (whatever NTFS version !) */ + /* to initialize security data */ + if (ntfs_open_secure(ctx->vol) && (ctx->vol->major_ver >= 3)) + failed_secure = "Could not open file $Secure"; + if (!ntfs_build_mapping(&ctx->security,ctx->usermap_path)) { +#if POSIXACLS + if (ctx->vol->secure_flags & (1 << SECURITY_DEFAULT)) + permissions_mode = "User mapping built, Posix ACLs not used"; + else { + permissions_mode = "User mapping built, Posix ACLs in use"; +#if KERNELACLS + if (strappend(&parsed_options, ",default_permissions,acl")) { + err = NTFS_VOLUME_SYNTAX_ERROR; + goto err_out; + } +#endif /* KERNELACLS */ + } +#else /* POSIXACLS */ +#if KERNELPERMS + if (!(ctx->vol->secure_flags & (1 << SECURITY_DEFAULT))) { + /* + * No explicit option but user mapping found + * force default security + */ + ctx->vol->secure_flags |= (1 << SECURITY_DEFAULT); + if (strappend(&parsed_options, ",default_permissions")) { + err = NTFS_VOLUME_SYNTAX_ERROR; + goto err_out; + } + } +#endif /* KERNELPERMS */ + permissions_mode = "User mapping built"; +#endif /* POSIXACLS */ + } else { + ctx->security.uid = ctx->uid; + ctx->security.gid = ctx->gid; + /* same ownership/permissions for all files */ + ctx->security.mapping[MAPUSERS] = (struct MAPPING*)NULL; + ctx->security.mapping[MAPGROUPS] = (struct MAPPING*)NULL; + if ((ctx->vol->secure_flags & (1 << SECURITY_WANTED)) + && !(ctx->vol->secure_flags & (1 << SECURITY_DEFAULT))) { + ctx->vol->secure_flags |= (1 << SECURITY_DEFAULT); + if (strappend(&parsed_options, ",default_permissions")) { + err = NTFS_VOLUME_SYNTAX_ERROR; + goto err_out; + } + } + if (ctx->vol->secure_flags & (1 << SECURITY_DEFAULT)) { + ctx->vol->secure_flags |= (1 << SECURITY_RAW); + permissions_mode = "Global ownership and permissions enforced"; + } else { + ctx->vol->secure_flags &= ~(1 << SECURITY_RAW); + permissions_mode = "Ownership and permissions disabled"; + } + } + if (ctx->usermap_path) + free (ctx->usermap_path); + + fh = mount_fuse(parsed_options); + if (!fh) { + err = NTFS_VOLUME_FUSE_ERROR; + goto err_out; + } + + ctx->mounted = TRUE; + +#if defined(linux) || defined(__uClinux__) + if (S_ISBLK(sbuf.st_mode) && (fstype == FSTYPE_FUSE)) + ntfs_log_info("%s", fuse26_kmod_msg); +#endif + setup_logging(parsed_options); + if (failed_secure) + ntfs_log_info("%s\n",failed_secure); + if (permissions_mode) + ntfs_log_info("%s, configuration type %d\n",permissions_mode, + 4 + POSIXACLS*6 - KERNELPERMS*3 + CACHEING); + if ((ctx->vol->secure_flags & (1 << SECURITY_RAW)) + && !ctx->uid && ctx->gid) + ntfs_log_error("Warning : using problematic uid==0 and gid!=0\n"); + + fuse_loop(fh); + + err = 0; + + fuse_unmount(opts.mnt_point, ctx->fc); + fuse_destroy(fh); +err_out: + ntfs_mount_error(opts.device, opts.mnt_point, err); + if (ctx->abs_mnt_point) + free(ctx->abs_mnt_point); +err2: + ntfs_close(); + free(ctx); + free(parsed_options); + free(opts.options); + free(opts.device); + return err; +} diff --git a/src/ntfs-3g.probe.8.in b/src/ntfs-3g.probe.8.in new file mode 100755 index 0000000..3e8a267 --- a/dev/null +++ b/src/ntfs-3g.probe.8.in @@ -0,0 +1,81 @@ +.\" Copyright (c) 2008 Szabolcs Szakacsits. +.\" This file may be copied under the terms of the GNU Public License. +.\" +.TH NTFS-3G.PROBE 8 "January 2008" "ntfs-3g.probe @VERSION@" +.SH NAME +ntfs-3g.probe \- Probe an NTFS volume mountability +.SH SYNOPSIS +.B ntfs-3g.probe +.I <\-\-readonly|\-\-readwrite> +.I volume +.br +.SH DESCRIPTION +The \fBntfs-3g.probe\fR utility tests a volume if it's NTFS mountable +read-only or read-write, and exits with a status value accordingly. +The \fIvolume\fR can be a block device or image file. +.SH OPTIONS +Below is a summary of the options that \fBntfs-3g.probe\fR accepts. +.TP +.B \-r, \-\-readonly +Test if the volume can be mounted read-only. +.TP +.B \-w, \-\-readwrite +Test if the volume can be mounted read-write. +.TP +.B \-h, \-\-help +Display help and exit. +.SH EXAMPLE +Test if /dev/sda1 can be mounted read-write: +.RS +.sp +.B ntfs-3g.probe --readwrite /dev/sda1 +.sp +.RE +.SH EXIT CODES +The exit codes are as follows: +.IP 0 +Volume is mountable. +.IP 11 +Syntax error, command line parsing failed. +.IP 12 +The volume doesn't have a valid NTFS. +.IP 13 +Inconsistent NTFS, hardware or device driver fault, or unsetup +SoftRAID/FakeRAID hardware. +.IP 14 +The NTFS partition is hibernated. +.IP 15 +The volume was not cleanly unmounted. +.IP 16 +The volume is already exclusively opened and in use by a kernel +driver or software. +.IP 17 +Unsetup SoftRAID/FakeRAID hardware. +.IP 18 +Unknown reason. +.IP 19 +Not enough privilege to mount. +.IP 20 +Out of memory. +.IP 21 +Unclassified FUSE error. +.SH KNOWN ISSUES +Please see +.RS +.sp +http://ntfs-3g.org/support.html +.sp +.RE +for common questions and known issues. +If you think you have found an undocumented problem in the latest release of +the software then please send an email describing it in detail. +You can contact the development team on the ntfs\-3g\-devel@lists.sf.net +address. +.SH AUTHORS +.B ntfs-3g.probe +was written by Szabolcs Szakacsits (szaka@ntfs-3g.org). +.SH THANKS +Alon Bar-Lev has integrated the utility into the NTFS-3G build process and +tested it with Erik Larsson before the public release. +.SH SEE ALSO +.BR ntfs-3g (8) diff --git a/src/ntfs-3g.probe.c b/src/ntfs-3g.probe.c new file mode 100755 index 0000000..592abd7 --- a/dev/null +++ b/src/ntfs-3g.probe.c @@ -0,0 +1,163 @@ +/** + * ntfs-3g.probe - Probe NTFS volume mountability + * + * Copyright (c) 2007-2009 Szabolcs Szakacsits + * + * 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 (in the main directory of the NTFS-3G + * distribution in the file COPYING); if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "config.h" + +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_ERRNO_H +#include +#endif +#include + +#include "compat.h" +#include "volume.h" +#include "misc.h" + +typedef enum { + PROBE_UNSET, + PROBE_READONLY, + PROBE_READWRITE +} probe_t; + +static struct options { + probe_t probetype; + char *device; +} opts; + +static const char *EXEC_NAME = "ntfs-3g.probe"; + +static const char *usage_msg = +"\n" +"%s %s - Probe NTFS volume mountability\n" +"\n" +"Copyright (C) 2007 Szabolcs Szakacsits\n" +"\n" +"Usage: %s <--readonly|--readwrite> \n" +"\n" +"Example: ntfs-3g.probe --readwrite /dev/sda1\n" +"\n" +"%s"; + +static int ntfs_open(const char *device) +{ + ntfs_volume *vol; + unsigned long flags = 0; + int ret = NTFS_VOLUME_OK; + + if (opts.probetype == PROBE_READONLY) + flags |= MS_RDONLY; + + vol = ntfs_mount(device, flags); + if (!vol) + ret = ntfs_volume_error(errno); + + ntfs_umount(vol, FALSE); + + return ret; +} + +static void usage(void) +{ + ntfs_log_info(usage_msg, EXEC_NAME, VERSION, EXEC_NAME, ntfs_home); +} + +static int parse_options(int argc, char *argv[]) +{ + int c; + + static const char *sopt = "-hrw"; + static const struct option lopt[] = { + { "readonly", no_argument, NULL, 'r' }, + { "readwrite", no_argument, NULL, 'w' }, + { "help", no_argument, NULL, 'h' }, + { NULL, 0, NULL, 0 } + }; + + opterr = 0; /* We handle errors. */ + opts.probetype = PROBE_UNSET; + + while ((c = getopt_long(argc, argv, sopt, lopt, NULL)) != -1) { + switch (c) { + case 1: /* A non-option argument */ + if (!opts.device) { + opts.device = ntfs_malloc(PATH_MAX + 1); + if (!opts.device) + return -1; + + strncpy(opts.device, optarg, PATH_MAX); + opts.device[PATH_MAX] = 0; + } else { + ntfs_log_error("%s: You must specify exactly " + "one device\n", EXEC_NAME); + return -1; + } + break; + case 'h': + usage(); + exit(0); + case 'r': + opts.probetype = PROBE_READONLY; + break; + case 'w': + opts.probetype = PROBE_READWRITE; + break; + default: + ntfs_log_error("%s: Unknown option '%s'.\n", EXEC_NAME, + argv[optind - 1]); + return -1; + } + } + + if (!opts.device) { + ntfs_log_error("ERROR: %s: Device is missing\n", EXEC_NAME); + return -1; + } + + if (opts.probetype == PROBE_UNSET) { + ntfs_log_error("ERROR: %s: Probe type is missing\n", EXEC_NAME); + return -1; + } + + return 0; +} + +int main(int argc, char *argv[]) +{ + int err; + + ntfs_log_set_handler(ntfs_log_handler_stderr); + + if (parse_options(argc, argv)) { + usage(); + exit(NTFS_VOLUME_SYNTAX_ERROR); + } + + err = ntfs_open(opts.device); + + free(opts.device); + exit(err); +} + diff --git a/src/ntfs-3g.secaudit.8.in b/src/ntfs-3g.secaudit.8.in new file mode 100755 index 0000000..79c05ac --- a/dev/null +++ b/src/ntfs-3g.secaudit.8.in @@ -0,0 +1,171 @@ +.\" Copyright (c) 2007-2009 Jean-Pierre André. +.\" This file may be copied under the terms of the GNU Public License. +.\" +.TH NTFS-3G.SECAUDIT 8 "February 2010" "ntfs-3g.secaudit 1.3.8" +.SH NAME +ntfs-3g.secaudit \- NTFS Security Data Auditing +.SH SYNOPSIS +.B ntfs-3g.secaudit +\fB[\fIoptions\fP\fB]\fR +.I args +.PP +Where \fIoptions\fP is a combination of : +.RS +-a full auditing of security data (Linux only) +.RE +.RS +-b backup ACLs +.RE +.RS +-e setting extra backed-up parameters (in conjunction with -s) +.RE +.RS +-h displaying hexadecimal security descriptors saved in a file +.RE +.RS +-r recursing in a directory +.RE +.RS +-s setting backed-up ACLs +.RE +.RS +-v verbose (very verbose if set twice) +.RE +.PP +and args define the parameters and the set of files acted upon. +.PP +Typing secaudit with no args will display a summary of available options. +.SH DESCRIPTION +\fBntfs-3g.secaudit\fR +displays the ownership and permissions of a set of files on an NTFS +file system, and checks their consistency. It can be started in terminal +mode only (no graphical user interface is available.) +.PP +When a \fIvolume\fR is required, it has to be unmounted, and the command +has to be issued as \fBroot\fP. The \fIvolume\fR can be either a block +device (i.e. a disk partition) or an image file. +.PP +When acting on a directory or volume, the command may produce a lot +of information. It is therefore advisable to redirect the output to +a file or pipe it to a text editor for examination. +.SH OPTIONS +Below are the valid combinations of options and arguments that +\fBntfs-3g.secaudit\fR accepts. All the indicated arguments are +mandatory and must be unique (if wildcards are used, they must +resolve to a single name.) +.TP +\fB-h\fP \fIfile\fP +Displays in an human readable form the hexadecimal security descriptors +saved in \fIfile\fP. This can be used to turn a verbose output into a very +verbose output. +.TP +\fB-a[rv]\fP \fIvolume\fP +Audits the volume : all the global security data on \fIvolume\fP are scanned +and errors are displayed. If option \fB-r\fP is present, all files and +directories are also scanned and their relations to global security data +are checked. This can produce a lot of data. + +This option is not effective on volumes formatted for old NTFS versions (pre +NTFS 3.0). Such volumes have no global security data. + +When errors are signalled, it is advisable to repair the volume with an +appropriate tool (such as \fBchkdsk\fP on Windows.) +.TP +\fB[-v]\fP \fIvolume\fP \fIfile\fP +Displays the security parameters of \fIfile\fP : its interpreted Linux mode +(rwx flags in octal) and Posix ACL[1], its security key if any, and its +security descriptor if verbose output. +.TP +\fB-r[v]\fP \fIvolume\fP \fIdirectory\fP +displays the security parameters of all files and subdirectories in +\fIdirectory\fP : their interpreted Linux mode (rwx flags in octal) and Posix +ACL[1], their security key if any, and their security descriptor if +verbose output. +.TP +.B -b[v] \fIvolume\fP \fI[directory]\fP +Recursively extracts to standard output the NTFS ACLs of files in \fIvolume\fP +and \fIdirectory\fP. +.TP +\fB-s[ev]\fP \fIvolume\fP \fI[backup-file]\fP +Sets the NTFS ACLS as indicated in \fIbackup-file\fP or standard input. The +input data must have been created on Linux. With option \fB-e\fP, also sets +extra parameters (currently Windows attrib). +.TP +\fIvolume\fP \fIperms\fP \fIfile\fP +Sets the security parameters of file to perms. Perms is the Linux +requested mode (rwx flags, expressed in octal form as in chmod) or +a Posix ACL[1] (expressed like in setfacl -m). This sets a new ACL +which is effective for Linux and Windows. +.TP +\fB-r[v]\fP \fIvolume\fP \fIperms\fP \fIdirectory\fP +Sets the security parameters of all files and subdirectories in +\fIdirectory\fP to \fIperms\fP. Perms is the Linux requested mode (rwx flags, +expressed in octal form as in \fBchmod\fP), or a Posix ACL[1] (expressed like +in \fBsetfacl -m\fP.) This sets new ACLs which are effective for Linux and +Windows. +.TP +\fB[-v]\fP \fImounted-file\fP +Displays the security parameters of \fImounted-file\fP : its interpreted +Linux mode (rwx flags in octal) and Posix ACL[1], its security key if any, +and its security descriptor if verbose output. This is a special case which +acts on a mounted file (or directory) and does not require being root. The +Posix ACL interpretation can only be displayed if the full path to +\fImounted-file\fP from the root of the global file tree is provided. +.SH NOTE +[1] provided the POSIX ACL option was selected at compile time. A Posix ACL +specification looks like "\fB[d:]{ugmo}:[id]:[perms],...\fP" where id is a +numeric user or group id, and perms an octal digit or a set from the letters +r, w and x. +.RS +Example : "\fBu::7,g::5,o:0,u:510:rwx,g:500:5,d:u:510:7\fP" +.SH EXAMPLES +Audit the global security data on /dev/sda1 +.RS +.sp +.B ntfs-3g.secaudit -ar /dev/sda1 +.sp +.RE +Display the ownership and permissions parameters for files in directory +/audio/music on device /dev/sda5, excluding sub-directories : +.RS +.sp +.B ntfs-3g.secaudit /dev/sda5 /audio/music +.sp +.RE +Set all files in directory /audio/music on device /dev/sda5 as writeable +by owner and read-only for everybody : +.RS +.sp +.B ntfs-3g.secaudit -r /dev/sda5 644 /audio/music +.sp +.RE +.SH EXIT CODES +.B ntfs-3g.secaudit +exits with a value of 0 when no error was detected, and with a value +of 1 when an error was detected. +.SH KNOWN ISSUES +Please see +.RS +.sp +http://www.tuxera.com/community/ntfs-3g-faq/ +.sp +.RE +for common questions and known issues. +If you would find a new one in the latest release of +the software then please send an email describing it +in detail. You can contact the +development team on the ntfs\-3g\-devel@lists.sf.net +address. +.SH AUTHORS +.B ntfs-3g.secaudit +has been developed by Jean-Pierre André. +.SH THANKS +Several people made heroic efforts, often over five or more +years which resulted the ntfs-3g driver. Most importantly they are +Anton Altaparmakov, Richard Russon, Szabolcs Szakacsits, Yura Pakhuchiy, +Yuval Fledel, and the author of the groundbreaking FUSE filesystem development +framework, Miklos Szeredi. +.SH SEE ALSO +.BR ntfsprogs (8), +.BR attr (5), +.BR getfattr (1) diff --git a/src/ntfs-3g.usermap.8.in b/src/ntfs-3g.usermap.8.in new file mode 100755 index 0000000..6efd47b --- a/dev/null +++ b/src/ntfs-3g.usermap.8.in @@ -0,0 +1,96 @@ +.\" Copyright (c) 2007-2009 Jean-Pierre André. +.\" This file may be copied under the terms of the GNU Public License. +.\" +.TH NTFS-3G.USERMAP 8 "February 2010" "ntfs-3g.usermap 1.1.2" +.SH NAME +ntfs-3g.usermap \- NTFS Building a User Mapping File +.SH SYNOPSIS +.B ntfs-3g.usermap +\fIwindows-system-device\fP +\fB[\fIother-ntfs-device\fP...\fB]\fR +.PP +Where \fIwindows-system-device\fP is the device containing the Windows system +whose users are to be mapped to current Linux system. +.PP +And \fIother-ntfs-device\fP is another device containing files which are +to be accessed both by the Windows mentioned above and current Linux system. +.PP +the ntfs-3g.usermap command must be started as root, and the designated devices +must not be mounted. +.PP +Typing ntfs-3g.usermap with no args will display a summary of command +arguments. +.SH DESCRIPTION +\fBntfs-3g.usermap\fR +creates the file defining the mapping of Windows accounts to Linux logins for +users who owns files which should be visible from both Windows and +Linux. +.PP +It relies on existing files which were created on Windows, trying +to locate significant files and asking which Linux user or group should +own them. When a Linux owner or group is requested, the reply may be : +.PP +- the uid or gid (numeric or symbolic) of Linux owner or group of the file. +.RS +In that situation, no more file with the same Windows owner will be selected. +.RE +- or no answer, when not able to define the owner or group. +.RS +In that situation another file owned by the same Windows user or group +may be selected later so that a mapping can be defined. +.RE +.PP +The mappings for standard Windows users, such as "Administrator" or +"All Users" are defined implicitly. As a consequence a user mapping should +never be defined as Linux root. +.PP +When there are no more significant files, ntfs-3g.usermap create the +mapping file into the file UserMapping in the current directory. This +file has to be moved to the hidden directory .NTFS-3G in the root of +all the NTFS file systems to be shared between Windows and Linux. This +requires the file system to be mounted, but the created file will not +be taken into account if not present at mount time, which means the +file system has to be unmounted and mounted again for the new mapping +file to be taken into account. +.SH OPTIONS +No option is defined for ntfs-3g.usermap. +.SH EXAMPLES +Map the users defined on the Windows system present on /dev/sda1 : +.RS +.sp +.B ntfs-3g.usermap /dev/sda1 +.sp +.RE +.PP +A detailed example, with screen displays is available on +http://pagesperso-orange.fr/b.andre/usermap.html +.SH EXIT CODES +.B ntfs-3g.usermap +exits with a value of 0 when no error was detected, and with a value +of 1 when an error was detected. +.SH KNOWN ISSUES +Please see +.RS +.sp +http://www.tuxera.com/community/ntfs-3g-faq/ +.sp +.RE +for common questions and known issues. +If you would find a new one in the latest release of +the software then please send an email describing it +in detail. You can contact the +development team on the ntfs\-3g\-devel@lists.sf.net +address. +.SH AUTHORS +.B ntfs-3g.secaudit +has been developed by Jean-Pierre André. +.SH THANKS +Several people made heroic efforts, often over five or more +years which resulted the ntfs-3g driver. Most importantly they are +Anton Altaparmakov, Richard Russon, Szabolcs Szakacsits, Yura Pakhuchiy, +Yuval Fledel, and the author of the groundbreaking FUSE filesystem development +framework, Miklos Szeredi. +.SH SEE ALSO +.BR ntfsprogs (8), +.BR attr (5), +.BR getfattr (1) diff --git a/src/secaudit.c b/src/secaudit.c new file mode 100755 index 0000000..3e098d5 --- a/dev/null +++ b/src/secaudit.c @@ -0,0 +1,7176 @@ +/* + * Display and audit security attributes in an NTFS volume + * + * Copyright (c) 2007-2010 Jean-Pierre Andre + * + * Options : + * -a auditing security data + * -b backing up NTFS ACLs + * -e set extra backed-up parameters (in conjunction with -s) + * -h displaying hexadecimal security descriptors within a file + * -r recursing in a directory + * -s setting backed-up NTFS ACLs + * -v verbose (very verbose if set twice) + * also, if compile-time option is set + * -t run internal tests (with no access to storage) + * + * On Linux (being root, with volume not mounted) : + * secaudit -h [file] + * display the security descriptors found in file + * secaudit -a[rv] volume + * audit the volume + * secaudit [-v] volume file + * display the security parameters of file + * secaudit -r[v] volume directory + * display the security parameters of files in directory + * secaudit -b[v] volume [directory] + * backup the security parameters of files in directory + * secaudit -s[ve] volume [backupfile] + * set the security parameters as indicated in backup + * with -e set extra parameters (Windows attrib) + * secaudit volume perms file + * set the security parameters of file to perms (mode or acl) + * secaudit -r[v] volume perms directory + * set the security parameters of files in directory to perms + * special case, does not require being root : + * secaudit [-v] mounted-file + * display the security parameters of mounted file + * + * + * On Windows (the volume being part of file name) + * secaudit -h [file] + * display the security descriptors found in file + * secaudit [-v] file + * display the security parameters of file + * secaudit -r[v] directory + * display the security parameters of files in directory + * secaudit -b[v] directory + * backup the security parameters of files in directory + * secaudit -s[v] [backupfile] + * set the security parameters as indicated in backup + * with -e set extra parameters (Windows attrib) + * secaudit perms file + * set the security parameters of file to perms (mode or acl) + * secaudit -r[v] perms directory + * set the security parameters of files in directory to perms + */ + +/* History + * + * Nov 2007 + * - first version, by concatenating miscellaneous utilities + * + * Jan 2008, version 1.0.1 + * - fixed mode displaying + * - added a global severe errors count + * + * Feb 2008, version 1.0.2 + * - implemented conversions for big-endian machines + * + * Mar 2008, version 1.0.3 + * - avoided consistency checks on $Secure when there is no such file + * + * Mar 2008, version 1.0.4 + * - changed ordering of ACE's + * - changed representation for special flags + * - defaulted to stdin for option -h + * - added self tests (compile time option) + * - fixed errors specific to big-endian computers + * + * Apr 2008, version 1.1.0 + * - developped Posix ACLs to NTFS ACLs conversions + * - developped NTFS ACLs backup and restore + * + * Apr 2008, version 1.1.1 + * - fixed an error specific to big-endian computers + * - checked hash value and fixed error report in restore + * - improved display in showhex() and restore() + * + * Apr 2008, version 1.1.2 + * - improved and fixed Posix ACLs to NTFS ACLs conversions + * + * Apr 2008, version 1.1.3 + * - reenabled recursion for setting a new mode or ACL + * - processed Unicode file names and displayed them as UTF-8 + * - allocated dynamically memory for file names when recursing + * + * May 2008, version 1.1.4 + * - all Unicode/UTF-8 strings checked and processed + * + * Jul 2008, version 1.1.5 + * - made Windows owner consistent with Linux owner when changing mode + * - allowed owner change on Windows when it does not match Linux owner + * - skipped currently unused code + * + * Aug 2008, version 1.2.0 + * - processed \.NTFS-3G\UserMapping on Windows + * - made use of user mappings through the security API or direct access + * - fixed a bug in restore + * - fixed UTF-8 conversions + * + * Sep 2008, version 1.3.0 + * - split the code to have part of it shared with ntfs-3g library + * - fixed testing for end of SDS block + * - added samples checking in selftest for easier debugging + * + * Oct 2008, version 1.3.1 + * - fixed outputting long long data when testing on a Palm organizer + * + * Dec 2008, version 1.3.2 + * - fixed restoring ACLs + * - added optional logging of ACL hashes to facilitate restore checks + * - fixed collecting SACLs + * - fixed setting special control flags + * - fixed clearing existing SACLs (Linux only) and DACLs + * - changed the sequencing of items when quering a security descriptor + * - avoided recursing on junctions and symlinks on Windows + * + * Jan 2009, version 1.3.3 + * - save/restore Windows attributes (code from Faisal) + * + * Mar 2009, version 1.3.4 + * - enabled displaying attributes of a mounted file over Linux + * + * Apr 2009, version 1.3.5 + * - fixed initialisation of stand-alone user mapping + * - fixed POSIXACL redefinition when included in the ntfs-3g package + * - fixed displaying of options + * - fixed a dependency on the shared library version used + * + * May 2009, version 1.3.6 + * - added new samples for self testing + * + * Jun 2009, version 1.3.7 + * - fixed displaying owner and group of a mounted file over Linux + * + * Jul 2009, version 1.3.8 + * - fixed again displaying owner and group of a mounted file over Linux + * - cleaned some code to avoid warnings + * + * Nov 2009, version 1.3.9 + * - allowed security descriptors up to 64K + * + * Nov 2009, version 1.3.10 + * - applied patches for MacOSX from Erik Larsson + * + * Nov 2009, version 1.3.11 + * - replace by (provided by glibc) + * + * Dec 2009, version 1.3.12 + * - worked around "const" possibly redefined in config.h + * + * Dec 2009, version 1.3.13 + * - fixed the return code of dorestore() + * + * Dec 2009, version 1.3.14 + * - adapted to opensolaris + * + * Jan 2010, version 1.3.15 + * - more adaptations to opensolaris + * - removed the fix for return code of dorestore() + * + * Jan 2010, version 1.3.16 + * - repeated the fix for return code of dorestore() + * + * Mar 2010, version 1.3.17 + * - fixed #ifdef'd code for selftest + */ + +/* + * 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 (in the main directory of the NTFS-3G + * distribution in the file COPYING); if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * General parameters which may have to be adapted to needs + */ + +#define AUDT_VERSION "1.3.17" + +#define GET_FILE_SECURITY "ntfs_get_file_security" +#define SET_FILE_SECURITY "ntfs_set_file_security" +#define GET_FILE_ATTRIBUTES "ntfs_get_file_attributes" +#define SET_FILE_ATTRIBUTES "ntfs_set_file_attributes" +#define READ_DIRECTORY "ntfs_read_directory" +#define READ_SDS "ntfs_read_sds" +#define READ_SII "ntfs_read_sii" +#define READ_SDH "ntfs_read_sdh" +#define GET_USER "ntfs_get_user" +#define GET_GROUP "ntfs_get_group" +#define GET_USID "ntfs_get_usid" +#define GET_GSID "ntfs_get_gsid" +#define INIT_FILE_SECURITY "ntfs_initialize_file_security" +#define LEAVE_FILE_SECURITY "ntfs_leave_file_security" + +/* + * External declarations + */ + +#include +#include +#include +#include +#ifdef HAVE_SYS_TYPES_H +#include +#endif + +#include +#include +#include + + /* + * integration into secaudit, check whether Win32, + * may have to be adapted to compiler or something else + */ + +#ifndef WIN32 +#if defined(__WIN32) | defined(__WIN32__) | defined(WNSC) +#define WIN32 1 +#endif +#endif + + /* + * integration into secaudit/Win32 + */ +#ifdef WIN32 +#include +#define __LITTLE_ENDIAN 1234 +#define __BYTE_ORDER __LITTLE_ENDIAN +#else + /* + * integration into secaudit/STSC + */ +#ifdef STSC +#include +#undef __BYTE_ORDER +#define __BYTE_ORDER __BIG_ENDIAN +#else + /* + * integration into secaudit/Linux + */ + +#include +#ifdef HAVE_ENDIAN_H +#include +#endif +#ifdef HAVE_MACHINE_ENDIAN_H +#include +#endif +#include +#include +#endif /* STSC */ +#endif /* WIN32 */ +#include "secaudit.h" + +#ifndef WIN32 + +#ifndef STSC + +#if !defined(HAVE_CONFIG_H) && POSIXACLS + /* require if not integrated into ntfs-3g package */ +#define HAVE_SETXATTR 1 +#endif + +#ifdef HAVE_CONFIG_H +#ifdef _FILE_OFFSET_BITS +#undef _FILE_OFFSET_BITS /* work around "_FILE_OFFSET_BITS" possibly already defined */ +#endif + /* according to config.h if integrated into ntfs-3g package */ +#include "config.h" +#ifdef const /* work around "const" possibly redefined in config.h */ +#undef const +#endif +#ifndef POSIXACLS +#define POSIXACLS 0 +#endif +#endif /* HAVE_CONFIG_H */ + +#ifdef HAVE_SETXATTR +#include +#else +#warning "The extended attribute package is not available" +#endif /* HAVE_SETXATTR */ + +#endif /* STSC */ + +#define MS_NONE 0 /* no flag for mounting the device */ +#define MS_RDONLY 1 /* flag for mounting the device read-only */ + +struct CALLBACK; + +typedef int (*dircallback)(struct CALLBACK *context, char *ntfsname, + int length, int type, long long pos, u64 mft_ref, + unsigned int dt_type); + +#if USESTUBS | defined(STSC) + +int ntfs_get_file_security(void *scapi, + const char *path, DWORD selection, + char *buf, DWORD buflen, LPDWORD psize); +BOOL ntfs_set_file_security(void *scapi, + const char *path, DWORD selection, const char *attr); +int ntfs_get_file_attributes(void *scapi, + const char *path); +BOOL ntfs_set_file_attributes(void *scapi, + const char *path, DWORD attrib); +BOOL ntfs_read_directory(void *scapi, + const char *path, dircallback callback, void *context); +int ntfs_read_sds(void *scapi, + char *buf, DWORD buflen, DWORD offset); +void *ntfs_read_sii(void *scapi, void *entry); +void *ntfs_read_sdh(void *scapi, void *entry); + +int ntfs_get_usid(void *scapi, uid_t uid, char *buf); +int ntfs_get_gsid(void *scapi, gid_t gid, char *buf); +int ntfs_get_user(void *scapi, const char *usid); +int ntfs_get_group(void *scapi, const char *gsid); + +void *ntfs_initialize_file_security(const char *device, int flags); +BOOL ntfs_leave_file_security(void *scapi); + +#else + +typedef int (*type_get_file_security)(void *scapi, + const char *path, DWORD selection, + char *buf, DWORD buflen, LPDWORD psize); +typedef BOOL (*type_set_file_security)(void *scapi, + const char *path, DWORD selection, const char *attr); +typedef int (*type_get_file_attributes)(void *scapi, + const char *path); +typedef BOOL (*type_set_file_attributes)(void *scapi, + const char *path, DWORD attrib); +typedef BOOL (*type_read_directory)(void *scapi, + const char *path, dircallback callback, void *context); +typedef int (*type_read_sds)(void *scapi, + char *buf, DWORD buflen, DWORD offset); +typedef void *(*type_read_sii)(void *scapi, void *entry); +typedef void *(*type_read_sdh)(void *scapi, void *entry); + +typedef int (*type_get_usid)(void *scapi, uid_t uid, char *buf); +typedef int (*type_get_gsid)(void *scapi, gid_t gid, char *buf); +typedef int (*type_get_user)(void *scapi, const char *usid); +typedef int (*type_get_group)(void *scapi, const char *gsid); + +typedef void *(*type_initialize_file_security)(const char *device, int flags); +typedef BOOL (*type_leave_file_security)(void *scapi); + +type_get_file_security ntfs_get_file_security; +type_set_file_security ntfs_set_file_security; +type_get_file_attributes ntfs_get_file_attributes; +type_set_file_attributes ntfs_set_file_attributes; +type_read_directory ntfs_read_directory; +type_read_sds ntfs_read_sds; +type_read_sii ntfs_read_sii; +type_read_sdh ntfs_read_sdh; + +type_get_usid ntfs_get_usid; +type_get_gsid ntfs_get_gsid; +type_get_user ntfs_get_user; +type_get_group ntfs_get_group; + +type_initialize_file_security ntfs_initialize_file_security; +type_leave_file_security ntfs_leave_file_security; + + +#endif /* USESTUBS | defined(STSC) */ +#endif /* WIN32 */ + +/* + * Prototypes for local functions + */ + +BOOL open_security_api(void); +BOOL close_security_api(void); +#ifndef WIN32 +BOOL open_volume(const char*, int flags); +BOOL close_volume(const char*); +#endif +unsigned int get2l(const char*, int); +unsigned long get4l(const char*, int); +u64 get6l(const char*, int); +u64 get6h(const char*, int); +u64 get8l(const char*, int); +void set2l(char*, unsigned int); +void set4l(char*, unsigned long); +void hexdump(const char*, int, int); +u32 hash(const le32*, int); +unsigned int utf8size(const char*, int); +unsigned int makeutf8(char*, const char*, int); +unsigned int utf16size(const char*); +unsigned int makeutf16(char*, const char*); +unsigned int utf16len(const char*); +void printname(FILE*, const char*); +void printerror(FILE*); +BOOL guess_dir(const char*); +void showsid(const char*, int, int); +void showusid(const char*, int); +void showgsid(const char*, int); +void showheader(const char*, int); +void showace(const char*, int, int, int); +void showacl(const char*, int, int, int); +void showdacl(const char*, int, int); +void showsacl(const char*, int, int); +void showall(const char*, int); +void showposix(const struct POSIX_SECURITY*); +int linux_permissions(const char*, BOOL); +uid_t linux_owner(const char*); +gid_t linux_group(const char*); +int basicread(void*, char*, size_t, off_t); +int dummyread(void*, char*, size_t, off_t); +int local_build_mapping(struct MAPPING *[], const char*); +void newblock(s32); +void freeblocks(void); +u32 getmsbhex(const char*); +u32 getlsbhex(const char*); +BOOL ishexdump(const char*, int, int); +void showhex(FILE*); +void showfull(const char*, BOOL); +BOOL applyattr(const char*, const char*, BOOL, int, s32); +BOOL restore(FILE*); +BOOL dorestore(const char*, FILE*); +u32 merge_rights(const struct POSIX_SECURITY*, BOOL); +void tryposix(struct POSIX_SECURITY*); +void check_samples(void); +void basictest(int, BOOL, const SID*, const SID*); +void posixtest(int, BOOL, const SID*, const SID*); +void selftests(void); +unsigned int getfull(char*, const char*); +BOOL updatefull(const char *name, DWORD flags, char *attr); +BOOL setfull(const char*, int, BOOL); +BOOL singleshow(const char*); +void showmounted(const char*); +BOOL recurseshow(const char*); +BOOL singleset(const char*, int); +BOOL recurseset(const char*, int); +#ifdef WIN32 +BOOL backup(const char*); +BOOL listfiles(const char*); +#if POSIXACLS +BOOL iterate(RECURSE, const char*, const struct POSIX_SECURITY*); +#else +BOOL iterate(RECURSE, const char*, mode_t); +#endif +#else +BOOL backup(const char*, const char*); +BOOL listfiles(const char*, const char*); +#endif +#if POSIXACLS +BOOL setfull_posix(const char *, const struct POSIX_SECURITY*, BOOL); +struct POSIX_SECURITY *linux_permissions_posix(const char*, BOOL); +BOOL recurseset_posix(const char*, const struct POSIX_SECURITY*); +BOOL singleset_posix(const char*, const struct POSIX_SECURITY*); +struct POSIX_SECURITY *encode_posix_acl(const char*); +#endif +static void stdfree(void*); + +BOOL valid_sds(const char*, unsigned int, unsigned int, + unsigned int, u32, BOOL); +BOOL valid_sii(const char*, u32); +BOOL valid_sdh(const char*, u32, u32); +int consist_sds(const char*, unsigned int, unsigned int, BOOL); +int consist_sii(const char*); +int consist_sdh(const char*); +int audit_sds(BOOL); +int audit_sii(void); +int audit_sdh(void); +void audit_summary(void); +BOOL audit(const char*); +int getoptions(int, char*[]); + +#ifndef WIN32 + +/* + * Structures for collecting directory contents (Linux only) + */ + +struct LINK { + struct LINK *next; + char name[1]; +} ; + +struct CALLBACK { + struct LINK *head; + const char *dir; +} ; + +int callback(struct CALLBACK *context, char *ntfsname, + int length, int type, long long pos, u64 mft_ref, + unsigned int dt_type); +#endif + +/* + * Global constants + */ + +#define BANNER "secaudit " AUDT_VERSION " : NTFS security data auditing" + +#if SELFTESTS & !USESTUBS + +/* + * Dummy mapping file (self tests only) + */ + +#define DUMMYAUTH "S-1-5-21-3141592653-589793238-462843383-" +char dummymapping[] = "500::" DUMMYAUTH "1000\n" + "501::" DUMMYAUTH "1001\n" + "502::" DUMMYAUTH "1002\n" + "503::" DUMMYAUTH "1003\n" + "516::" DUMMYAUTH "1016\n" + ":500:" DUMMYAUTH "513\r\n" + ":511:S-1-5-21-1607551490-981732888-1819828000-513\n" + ":516:" DUMMYAUTH "1012\r\n" + "::" DUMMYAUTH "10000\n"; + +/* + * SID for world (S-1-1-0) + */ + +static const char worldsidbytes[] = { + 1, /* revision */ + 1, /* auth count */ + 0, 0, 0, 0, 0, 1, /* base */ + 0, 0, 0, 0 /* 1st level */ +} ; +static const SID *worldsid = (const SID*)worldsidbytes; + +/* + * SID for administrator + */ + +static const char adminsidbytes[] = { + 1, /* revision */ + 2, /* auth count */ + 0, 0, 0, 0, 0, 5, /* base */ + 32, 0, 0, 0, /* 1st level */ + 32, 2, 0, 0 /* 2nd level */ +}; + +static const SID *adminsid = (const SID*)adminsidbytes; + +/* + * SID for system + */ + +static const char systemsidbytes[] = { + 1, /* revision */ + 1, /* auth count */ + 0, 0, 0, 0, 0, 5, /* base */ + 18, 0, 0, 0 /* 1st level */ + }; + +static const SID *systemsid = (const SID*)systemsidbytes; + +#endif + +/* + * Global variables + */ + +BOOL opt_a; /* audit security data */ +BOOL opt_b; /* backup NTFS ACLs */ +BOOL opt_e; /* restore extra (currently windows attribs) */ +BOOL opt_h; /* display an hexadecimal descriptor in a file */ +BOOL opt_r; /* recursively apply to subdirectories */ +BOOL opt_s; /* restore NTFS ACLs */ +#if SELFTESTS & !USESTUBS +BOOL opt_t; /* run self-tests */ +#endif +int opt_v; /* verbose or very verbose*/ +struct SECURITY_DATA *securdata[(MAXSECURID + (1 << SECBLKSZ) - 1)/(1 << SECBLKSZ)]; +#if FORCEMASK +BOOL opt_m; /* force a mask - dangerous */ +u32 forcemsk /* mask to force */ +#endif +unsigned int errors; /* number of severe errors */ +unsigned int warnings; /* number of non-severe errors */ + +struct CHKALLOC *firstalloc; +struct SECURITY_CONTEXT context; +MAPTYPE mappingtype; + +#ifdef STSC +#define static +#endif + +#ifndef WIN32 + +void *ntfs_handle; +void *ntfs_context = (void*)NULL; + +/* + * Open and close the security API (platform dependent) + */ + +BOOL open_security_api(void) +{ +#if USESTUBS | defined(STSC) + return (TRUE); +#else + char *error; + BOOL err; + const char *libfile; + + err = TRUE; + libfile = getenv(ENVNTFS3G); + if (!libfile) + libfile = (sizeof(char*) == 8 ? LIBFILE64 : LIBFILE); + ntfs_handle = dlopen(libfile,RTLD_LAZY); + if (ntfs_handle) { + ntfs_initialize_file_security = (type_initialize_file_security) + dlsym(ntfs_handle,INIT_FILE_SECURITY); + error = dlerror(); + if (error) + fprintf(stderr," %s\n",error); + else { + ntfs_leave_file_security = (type_leave_file_security) + dlsym(ntfs_handle,LEAVE_FILE_SECURITY); + ntfs_get_file_security = (type_get_file_security) + dlsym(ntfs_handle,GET_FILE_SECURITY); + ntfs_set_file_security = (type_set_file_security) + dlsym(ntfs_handle,SET_FILE_SECURITY); + ntfs_get_file_attributes = (type_get_file_attributes) + dlsym(ntfs_handle,GET_FILE_ATTRIBUTES); + ntfs_set_file_attributes = (type_set_file_attributes) + dlsym(ntfs_handle,SET_FILE_ATTRIBUTES); + ntfs_read_directory = (type_read_directory) + dlsym(ntfs_handle,READ_DIRECTORY); + ntfs_read_sds = (type_read_sds) + dlsym(ntfs_handle,READ_SDS); + ntfs_read_sii = (type_read_sii) + dlsym(ntfs_handle,READ_SII); + ntfs_read_sdh = (type_read_sdh) + dlsym(ntfs_handle,READ_SDH); + ntfs_get_user = (type_get_user) + dlsym(ntfs_handle,GET_USER); + ntfs_get_group = (type_get_group) + dlsym(ntfs_handle,GET_GROUP); + ntfs_get_usid = (type_get_usid) + dlsym(ntfs_handle,GET_USID); + ntfs_get_gsid = (type_get_gsid) + dlsym(ntfs_handle,GET_GSID); + err = !ntfs_initialize_file_security + || !ntfs_leave_file_security + || !ntfs_get_file_security + || !ntfs_set_file_security + || !ntfs_get_file_attributes + || !ntfs_set_file_attributes + || !ntfs_read_directory + || !ntfs_read_sds + || !ntfs_read_sii + || !ntfs_read_sdh + || !ntfs_get_user + || !ntfs_get_group + || !ntfs_get_usid + || !ntfs_get_gsid; + + if (error) + fprintf(stderr,"ntfs-3g API not available\n"); + } + } else { + fprintf(stderr,"Could not open ntfs-3g library\n"); + fprintf(stderr,"\nPlease set environment variable \"" ENVNTFS3G "\"\n"); + fprintf(stderr,"to appropriate path and retry\n"); + } + return (!err); +#endif /* USESTUBS | defined(STSC) */ +} + +BOOL close_security_api(void) +{ +#if USESTUBS | defined(STSC) + return (0); +#else + return (!dlclose(ntfs_handle)); +#endif /* USESTUBS | defined(STSC) */ +} + +/* + * Open and close a volume (platform dependent) + * Assumes a single volume is opened + */ + +BOOL open_volume(const char *volume, int flags) +{ + BOOL ok; + + ok = FALSE; + if (!ntfs_context) { + ntfs_context = (*ntfs_initialize_file_security)(volume,flags); + if (ntfs_context) { + if (*(u32*)ntfs_context != MAGIC_API) { + fprintf(stderr,"Versions of ntfs-3g and secaudit" + " are not compatible\n"); + } else { + fprintf(stderr,"\"%s\" opened\n",volume); + mappingtype = MAPEXTERN; + ok = TRUE; + } + } else { + fprintf(stderr,"Could not open \"%s\"\n",volume); + fprintf(stderr,"Make sure \"%s\" is not mounted\n",volume); + } + } else + fprintf(stderr,"A volume is already open\n"); + return (ok); +} + +BOOL close_volume(const char *volume) +{ + BOOL r; + + r = (*ntfs_leave_file_security)(ntfs_context); + if (r) + fprintf(stderr,"\"%s\" closed\n",volume); + else + fprintf(stderr,"Could not close \"%s\"\n",volume); + ntfs_context = (void*)NULL; + return (r); +} + +#endif /* WIN32 */ + +/* + * Extract small or big endian data from an array of bytes + */ + +unsigned int get2l(const char *attr, int p) +{ + int i; + unsigned int v; + + v = 0; + for (i=0; i<2; i++) + v += (attr[p+i] & 255) << (8*i); + return (v); +} + +unsigned long get4l(const char *attr, int p) +{ + int i; + unsigned long v; + + v = 0; + for (i=0; i<4; i++) + v += ((long)(attr[p+i] & 255)) << (8*i); + return (v); +} + +u64 get6l(const char *attr, int p) +{ + int i; + u64 v; + + v = 0; + for (i=0; i<6; i++) + v += ((long long)(attr[p+i] & 255)) << (8*i); + return (v); +} + +u64 get6h(const char *attr, int p) +{ + int i; + u64 v; + + v = 0; + for (i=0; i<6; i++) + v = (v << 8) + (attr[p+i] & 255); + return (v); +} + +u64 get8l(const char *attr, int p) +{ + int i; + u64 v; + + v = 0; + for (i=0; i<8; i++) + v += ((long long)(attr[p+i] & 255)) << (8*i); + return (v); +} + +/* + * Set small or big endian data into an array of bytes + */ + +void set2l(char *p, unsigned int v) +{ + int i; + + for (i=0; i<2; i++) + p[i] = ((v >> 8*i) & 255); +} + +void set4l(char *p, unsigned long v) +{ + int i; + + for (i=0; i<4; i++) + p[i] = ((v >> 8*i) & 255); +} + + +/* + * hexadecimal dump of an array of bytes + */ + +void hexdump(const char *attr, int size, int level) +{ + int i,j; + + for (i=0; i> 29) & 7); + return (h); +} + +/* + * Evaluate the size of UTS-8 conversion of a UTF-16LE text + * trailing '\0' not accounted for + * Returns 0 for invalid input + */ + +unsigned int utf8size(const char *utf16, int length) +{ + int i; + unsigned int size; + enum { BASE, SURR, ERR } state; + + size = 0; + state = BASE; + for (i=0; i<2*length; i+=2) { + switch (state) { + case BASE : + if (utf16[i+1] & 0xf8) { + if ((utf16[i+1] & 0xf8) == 0xd8) + state = (utf16[i+1] & 4 ? ERR : SURR); + else +#if NOREVBOM + if (((utf16[i+1] & 0xff) == 0xff) + && ((utf16[i] & 0xfe) == 0xfe)) + state = ERR; + else + size += 3; +#else + size += 3; +#endif + } else + if ((utf16[i] & 0x80) || utf16[i+1]) + size += 2; + else + size++; + break; + case SURR : + if ((utf16[i+1] & 0xfc) == 0xdc) { + state = BASE; + size += 4; + } else + state = ERR; + break; + case ERR : + break; + } + } + if (state != BASE) + size = 0; + return (size); +} + +/* + * Convert a UTF-16LE text to UTF-8 + * Note : wcstombs() not used because on Linux it fails for characters + * not present in current locale + * Returns size or zero for invalid input + */ + +unsigned int makeutf8(char *utf8, const char *utf16, int length) +{ + int i; + unsigned int size; + unsigned int rem; + enum { BASE, SURR, ERR } state; + + size = 0; + rem = 0; + state = BASE; + for (i=0; i<2*length; i+=2) { + switch (state) { + case BASE : + if (utf16[i+1] & 0xf8) { + if ((utf16[i+1] & 0xf8) == 0xd8) { + if (utf16[i+1] & 4) + state = ERR; + else { + utf8[size++] = 0xf0 + (utf16[i+1] & 7) + + ((utf16[i] & 0xc0) == 0xc0); + utf8[size++] = 0x80 + (((utf16[i] + 64) >> 2) & 63); + rem = utf16[i] & 3; + state = SURR; + } + } else { +#if NOREVBOM + if (((utf16[i+1] & 0xff) == 0xff) + && ((utf16[i] & 0xfe) == 0xfe)) + state = ERR; + else { + utf8[size++] = 0xe0 + ((utf16[i+1] >> 4) & 15); + utf8[size++] = 0x80 + + ((utf16[i+1] & 15) << 2) + + ((utf16[i] >> 6) & 3); + utf8[size++] = 0x80 + (utf16[i] & 63); + } +#else + utf8[size++] = 0xe0 + ((utf16[i+1] >> 4) & 15); + utf8[size++] = 0x80 + + ((utf16[i+1] & 15) << 2) + + ((utf16[i] >> 6) & 3); + utf8[size++] = 0x80 + (utf16[i] & 63); +#endif + } + } else + if ((utf16[i] & 0x80) || utf16[i+1]) { + utf8[size++] = 0xc0 + + ((utf16[i+1] & 15) << 2) + + ((utf16[i] >> 6) & 3); + utf8[size++] = 0x80 + (utf16[i] & 63); + } else + utf8[size++] = utf16[i]; + break; + case SURR : + if ((utf16[i+1] & 0xfc) == 0xdc) { + utf8[size++] = 0x80 + (rem << 4) + + ((utf16[i+1] & 3) << 2) + + ((utf16[i] >> 6) & 3); + utf8[size++] = 0x80 + (utf16[i] & 63); + state = BASE; + } else + state = ERR; + break; + case ERR : + break; + } + } + utf8[size] = 0; + if (state != BASE) + state = ERR; + return (state == ERR ? 0 : size); +} + +#ifdef WIN32 + +/* + * Evaluate the size of UTF-16LE conversion of a UTF-8 text + * (basic conversions only) + * trailing '\0' not accounted for + */ + +unsigned int utf16size(const char *utf8) +{ + unsigned int size; + const char *p; + int c; + unsigned int code; + enum { BASE, TWO, THREE, THREE2, THREE3, FOUR, ERR } state; + + p = utf8; + size = 0; + state = BASE; + while (*p) { + c = *p++ & 255; + switch (state) { + case BASE : + if (!(c & 0x80)) + size++; + else + if (c < 0xc2) + state = ERR; + else + if (c < 0xe0) + state = TWO; + else + if (c < 0xf0) { + if (c == 0xe0) + state = THREE2; + else + if (c == 0xed) + state = THREE3; + else + state = THREE; + } else + if (c < 0xf8) { + state = FOUR; + code = c & 7; + } else + state = ERR; + break; + case TWO : + if ((c & 0xc0) != 0x80) + state = ERR; + else { + size++; + state = BASE; + } + break; + case THREE : + if ((c & 0xc0) != 0x80) + state = ERR; + else + state = TWO; + break; + case THREE2 : + if ((c & 0xe0) != 0xa0) + state = ERR; + else + state = TWO; + break; + case THREE3 : + if ((c & 0xe0) != 0x80) + state = ERR; + else + state = TWO; + break; + case FOUR : + if ((((code << 6) + (c & 63)) > 0x10f) + || (((code << 6) + (c & 63)) < 0x10)) + state = ERR; + else { + size++; + state = THREE; + } + break; + case ERR : + break; + } + } + if (state != BASE) size = 0; + return (size); +} + +/* + * Convert a UTF8 text to UTF-16LE + * (basic conversions only) + * Note : mbstowcs() not used because on Linux it fails for characters + * not present in current locale + */ + +unsigned int makeutf16(char *target, const char *utf8) +{ + unsigned int size; + unsigned int code; + const char *p; + int c; + enum { BASE, TWO, THREE, THREE2, THREE3, FOUR, FOUR2, FOUR3, ERR } state; + + p = utf8; + size = 0; + c = 0; + state = BASE; + while (*p) { + c = *p++ & 255; + switch (state) { + case BASE : + if (!(c & 0x80)) { + target[2*size] = c; + target[2*size + 1] = 0; + size++; + } else { + if (c < 0xc2) + state = ERR; + else + if (c < 0xe0) { + code = c & 31; + state = TWO; + } else + if (c < 0xf0) { + code = c & 15; + if (c == 0xe0) + state = THREE2; + else + if (c == 0xed) + state = THREE3; + else + state = THREE; + } else + if (c < 0xf8) { + code = c & 7; + state = FOUR; + } else + state = ERR; + } + break; + case TWO : +#if NOREVBOM + if (((c & 0xc0) != 0x80) + || ((code == 0x3ff) && (c >= 0xbe))) +#else + if ((c & 0xc0) != 0x80) +#endif + state = ERR; + else { + target[2*size] = ((code & 3) << 6) + (c & 63); + target[2*size + 1] = ((code >> 2) & 255); + size++; + state = BASE; + } + break; + case THREE : + if ((c & 0xc0) != 0x80) + state = ERR; + else { + code = ((code & 15) << 6) + (c & 63); + state = TWO; + } + break; + case THREE2 : + if ((c & 0xe0) != 0xa0) + state = ERR; + else { + code = ((code & 15) << 6) + (c & 63); + state = TWO; + } + break; + case THREE3 : + if ((c & 0xe0) != 0x80) + state = ERR; + else { + code = ((code & 15) << 6) + (c & 63); + state = TWO; + } + break; + case FOUR : + if ((c & 0xc0) != 0x80) + state = ERR; + else { + code = (code << 6) + (c & 63); + state = FOUR2; + } + break; + case FOUR2 : + if ((c & 0xc0) != 0x80) + state = ERR; + else { + code = (code << 6) + (c & 63); + state = FOUR3; + } + break; + case FOUR3 : + if ((code > 0x43ff) + || (code < 0x400) + || ((c & 0xc0) != 0x80)) + state = ERR; + else { + target[2*size] = ((code - 0x400) >> 4) & 255; + target[2*size+1] = 0xd8 + (((code - 0x400) >> 12) & 3); + target[2*size+2] = ((code & 3) << 6) + (c & 63); + target[2*size+3] = 0xdc + ((code >> 2) & 3); + size += 2; + state = BASE; + } + break; + case ERR : + break; + } + } + if (state != BASE) + size = 0; + target[2*size] = 0; + target[2*size + 1] = 0; + return (size); +} + +unsigned int utf16len(const char *str) +{ + unsigned int len; + + len = 0; + while (str[2*len] || str[2*len+1]) len++; + return (len); +} + +#endif + +/* + * Print a file name + * on Windows it prints UTF-16LE names as UTF-8 + */ + +void printname(FILE *file, const char *name) +{ +#ifdef WIN32 + char utf8name[MAXFILENAME]; + + makeutf8(utf8name,name,utf16len(name)); + fprintf(file,"%s",utf8name); +#else + fprintf(file,"%s",name); +#endif +} + +/* + * Print the last error code + */ + +void printerror(FILE *file) +{ +#ifdef WIN32 + int err; + const char *txt; + + err = GetLastError(); + switch (err) { + case 5 : + txt = "Access to security descriptor was denied"; + break; + case 1307 : + txt = "This SID may not be assigned as the owner of this object"; + break; + case 1308 : + txt = "This SID may not be assigned as the group of this object"; + break; + case 1314 : + txt = "You do not have the privilege to change this SID"; + break; + default : + txt = (const char*)NULL; + break; + } + if (txt) + fprintf(file,"Error %d : %s\n",err,txt); + else + fprintf(file,"Error %d\n",err); +#else +#ifdef STSC + if (errno) fprintf(file,"Error code %d\n",errno); +#else + if (errno) fprintf(file,"Error code %d : %s\n",errno,strerror(errno)); +#endif +#endif +} + +/* + * Guess whether a security attribute is intended for a directory + * based on the presence of inheritable ACE + * (not 100% reliable) + */ + +BOOL guess_dir(const char *attr) +{ + int off; + int isdir; + int cnt; + int i; + int x; + + isdir = 0; + off = get4l(attr,16); + if (off) { + cnt = get2l(attr,off+4); + x = 8; + for (i=0; i> 16) & 127); + if (rights & 0x10000) + printf("%*cDelete\n",-level-8,marker); + if (rights & 0x20000) + printf("%*cRead control\n",-level-8,marker); + if (rights & 0x40000) + printf("%*cWrite DAC\n",-level-8,marker); + if (rights & 0x80000) + printf("%*cWrite owner\n",-level-8,marker); + if (rights & 0x100000) + printf("%*cSynchronize\n",-level-8,marker); + if (rights & 0x800000) + printf("%*cCan access security ACL\n",-level-4,marker); + if (rights & 0x10000000) + printf("%*cGeneric all\n",-level-4,marker); + if (rights & 0x20000000) + printf("%*cGeneric execute\n",-level-4,marker); + if (rights & 0x40000000) + printf("%*cGeneric write\n",-level-4,marker); + if (rights & 0x80000000) + printf("%*cGeneric read\n",-level-4,marker); + + printf("%*cSID at 0x%x\n",-level,marker,off+8); + showsid(attr,off+8,level+4); + printf("%*cSummary :",-level,marker); + if (attr[off] == 0) + printf(" grant"); + if (attr[off] == 1) + printf(" deny"); + if (rights & le32_to_cpu(FILE_GREAD | FILE_GWRITE | FILE_GEXEC)) { + printf(" "); + if (rights & le32_to_cpu(FILE_GREAD)) + printf("r"); + if (rights & le32_to_cpu(FILE_GWRITE)) + printf("w"); + if (rights & le32_to_cpu(FILE_GEXEC)) + printf("x"); + } else + printf(" none"); + if (flags & 11) + printf(" inherited"); + if (!(flags & 8)) { + int sz; + + printf(" applied"); + sz = attr[off+9]*4 + 8; + if (!memcmp(&attr[off+8],&attr[get4l(attr,4)],sz)) + printf(" to owner"); + if (!memcmp(&attr[off+8],&attr[get4l(attr,8)],sz)) + printf(" to group"); + } + printf("\n"); + +} + +void showacl(const char *attr, int off, int isdir, int level) +{ + int i; + int cnt; + int size; + int x; + char marker; + + if (opt_b) + marker = '#'; + else + marker = ' '; + size = get2l(attr,off+2); + printf("%*crevision %d\n",-level,marker,attr[off]); + printf("%*cACL size %d\n",-level,marker,size); + cnt = get2l(attr,off+4); + printf("%*cACE cnt %d\n",-level,marker,cnt); + x = 8; + for (i=0; (iacccnt; + defcnt = pxdesc->defcnt; + firstdef = pxdesc->firstdef; + acl = &pxdesc->acl; + printf("Posix descriptor :\n"); + printf(" acccnt %d\n",acccnt); + printf(" defcnt %d\n",defcnt); + printf(" firstdef %d\n",firstdef); + printf(" mode : 0%03o\n",(int)pxdesc->mode); + printf(" tagsset : 0x%02x\n",(int)pxdesc->tagsset); + printf("Posix ACL :\n"); + printf(" version %d\n",(int)acl->version); + printf(" flags 0x%02x\n",(int)acl->flags); + for (k=0; k<(acccnt + defcnt); k++) { + if (k < acccnt) + l = k; + else + l = firstdef + k - acccnt; + pxace = &acl->ace[l]; + tag = pxace->tag; + perms = pxace->perms; + if (tag == POSIX_ACL_SPECIAL) { + txperm[0] = (perms & S_ISVTX ? 's' : '-'); + txperm[1] = (perms & S_ISUID ? 'u' : '-'); + txperm[2] = (perms & S_ISGID ? 'g' : '-'); + } else { + txperm[0] = (perms & 4 ? 'r' : '-'); + txperm[1] = (perms & 2 ? 'w' : '-'); + txperm[2] = (perms & 1 ? 'x' : '-'); + } + txperm[3] = 0; + if (k >= acccnt) + txtype = "default"; + else + txtype = "access "; + switch (tag) { + case POSIX_ACL_USER : + txtag = "USER "; + break; + case POSIX_ACL_USER_OBJ : + txtag = "USR-O"; + break; + case POSIX_ACL_GROUP : + txtag = "GROUP"; + break; + case POSIX_ACL_GROUP_OBJ : + txtag = "GRP-O"; + break; + case POSIX_ACL_MASK : + txtag = "MASK "; + break; + case POSIX_ACL_OTHER : + txtag = "OTHER"; + break; + case POSIX_ACL_SPECIAL : + txtag = "SPECL"; + break; + default : + txtag = "UNKWN"; + break; + } + id = pxace->id; + printf("ace %d : %s %s %4ld perms 0%03o %s\n", + l,txtype,txtag,(long)id, + perms,txperm); + } + } else + printf("** NULL ACL\n"); +} + +#endif /* POSIXACLS */ + +#if defined(WIN32) | defined(STSC) + +#else + +/* + * Relay to get usid as defined during mounting + */ + +const SID *relay_find_usid(const struct MAPPING *usermapping __attribute__((unused)), + uid_t uid, SID *defusid) +{ + return (ntfs_get_usid(ntfs_context,uid,(char*)defusid) ? + defusid : (SID*)NULL); +} + +/* + * Relay to get gsid as defined during mounting + */ + +const SID *relay_find_gsid(const struct MAPPING *groupmapping __attribute__((unused)), + uid_t gid, SID *defgsid) +{ + return (ntfs_get_usid(ntfs_context,gid,(char*)defgsid) ? + defgsid : (SID*)NULL); +} + +/* + * Relay to get uid as defined during mounting + */ + +uid_t relay_find_user(const struct MAPPING *mapping __attribute__((unused)), + const SID *usid) +{ + int uid; + + uid = ntfs_get_user(ntfs_context,(const char*)usid); + return (uid < 0 ? 0 : uid); +} + +/* + * Relay to get gid as defined during mounting + */ + +gid_t relay_find_group(const struct MAPPING *mapping __attribute__((unused)), + const SID *gsid) +{ + int gid; + + gid = ntfs_get_group(ntfs_context,(const char*)gsid); + return (gid < 0 ? 0 : gid); +} + +#endif + +#if defined(WIN32) | defined(STSC) + +/* + * Dummy get uid from user name, out of a Linux environment + */ + +struct passwd *getpwnam(const char *user) +{ + ntfs_log_error("Cannot interpret id \"%s\"", user); + ntfs_log_error("please use numeric uids in UserMapping file\n"); + return ((struct passwd*)NULL); +} + +/* + * Dummy get gid from group name, out of a Linux environment + */ + +struct group *getgrnam(const char *group) +{ + ntfs_log_error("Cannot interpret id \"%s\"", group); + ntfs_log_error("please use numeric gids in UserMapping file\n"); + return ((struct group*)NULL); +} + +#endif /* defined(WIN32) | defined(STSC) */ + +#if POSIXACLS + +struct POSIX_SECURITY *linux_permissions_posix(const char *attr, BOOL isdir) +{ + const SECURITY_DESCRIPTOR_RELATIVE *phead; +#if OWNERFROMACL + const SID *osid; +#endif + const SID *usid; + const SID *gsid; + struct POSIX_SECURITY *posix_desc; + + phead = (const SECURITY_DESCRIPTOR_RELATIVE*)attr; + gsid = (const SID*)&attr[le32_to_cpu(phead->group)]; +#if OWNERFROMACL + osid = (const SID*)&attr[le32_to_cpu(phead->owner)]; + usid = ntfs_acl_owner((const char*)attr); +#if SELFTESTS & !USESTUBS + if (!opt_t && !ntfs_same_sid(usid,osid)) + printf("== Linux owner is different from Windows owner\n"); +#else + if (!ntfs_same_sid(usid,osid)) + printf("== Linux owner is different from Windows owner\n"); +#endif +#else + usid = (const SID*)&attr[le32_to_cpu(phead->owner)]; +#endif + posix_desc = ntfs_build_permissions_posix(context.mapping, + (const char*)attr, usid, gsid, isdir); + if (!posix_desc) { + printf("** Failed to build a Posix descriptor\n"); + errors++; + } + return (posix_desc); +} + +#endif /* POSIXACLS */ + +int linux_permissions(const char *attr, BOOL isdir) +{ + const SECURITY_DESCRIPTOR_RELATIVE *phead; +#if OWNERFROMACL + const SID *osid; +#endif + const SID *usid; + const SID *gsid; + int perm; + + phead = (const SECURITY_DESCRIPTOR_RELATIVE*)attr; + gsid = (const SID*)&attr[le32_to_cpu(phead->group)]; +#if OWNERFROMACL + osid = (const SID*)&attr[le32_to_cpu(phead->owner)]; + usid = ntfs_acl_owner((const char*)attr); +#if SELFTESTS & !USESTUBS + if (!opt_t && !ntfs_same_sid(usid,osid)) + printf("== Linux owner is different from Windows owner\n"); +#else + if (!ntfs_same_sid(usid,osid)) + printf("== Linux owner is different from Windows owner\n"); +#endif +#else + usid = (const SID*)&attr[le32_to_cpu(phead->owner)]; +#endif + perm = ntfs_build_permissions((const char*)attr, usid, gsid, isdir); + if (perm < 0) { + printf("** Failed to build permissions\n"); + errors++; + } + return (perm); +} + +uid_t linux_owner(const char *attr) +{ + const SECURITY_DESCRIPTOR_RELATIVE *phead; + const SID *usid; + uid_t uid; + + phead = (const SECURITY_DESCRIPTOR_RELATIVE*)attr; +#if OWNERFROMACL + usid = ntfs_acl_owner((const char*)attr); +#else + usid = (const SID*)&attr[le32_to_cpu(phead->owner)]; +#endif +#if defined(WIN32) | defined(STSC) + uid = ntfs_find_user(context.mapping[MAPUSERS],usid); +#else + if (mappingtype == MAPEXTERN) + uid = relay_find_user(context.mapping[MAPUSERS],usid); + else + uid = ntfs_find_user(context.mapping[MAPUSERS],usid); +#endif + return (uid); +} + +gid_t linux_group(const char *attr) +{ + const SECURITY_DESCRIPTOR_RELATIVE *phead; + const SID *gsid; + gid_t gid; + + phead = (const SECURITY_DESCRIPTOR_RELATIVE*)attr; + gsid = (const SID*)&attr[le32_to_cpu(phead->group)]; +#if defined(WIN32) | defined(STSC) + gid = ntfs_find_group(context.mapping[MAPGROUPS],gsid); +#else + if (mappingtype == MAPEXTERN) + gid = relay_find_group(context.mapping[MAPGROUPS],gsid); + else + gid = ntfs_find_group(context.mapping[MAPGROUPS],gsid); +#endif + return (gid); +} + +void newblock(s32 key) +{ + struct SECURITY_DATA *psecurdata; + int i; + + if ((key > 0) && (key < MAXSECURID) && !securdata[key >> SECBLKSZ]) { + securdata[key >> SECBLKSZ] = + (struct SECURITY_DATA*)malloc((1 << SECBLKSZ)*sizeof(struct SECURITY_DATA)); + if (securdata[key >> SECBLKSZ]) + for (i=0; i<(1 << SECBLKSZ); i++) { + psecurdata = &securdata[key >> SECBLKSZ][i]; + psecurdata->filecount = 0; + psecurdata->mode = 0; + psecurdata->flags = 0; + psecurdata->attr = (char*)NULL; + } + } +} + +void freeblocks(void) +{ + int i,j; + struct SECURITY_DATA *psecurdata; + + for (i=0; i<(MAXSECURID + (1 << SECBLKSZ) - 1)/(1 << SECBLKSZ); i++) + if (securdata[i]) { + for (j=0; j<(1 << SECBLKSZ); j++) { + psecurdata = &securdata[i][j]; + if (psecurdata->attr) + free(psecurdata->attr); + } + free(securdata[i]); + } +} + +/* + * Basic read from a user mapping file (Win32) + */ + +int basicread(void *fileid, char *buf, size_t size, + off_t pos __attribute__((unused))) +{ + return (read(*(int*)fileid, buf, size)); +} + +#if SELFTESTS & !USESTUBS + +/* + * Read a dummy mapping file for tests + */ + +int dummyread(void *fileid __attribute__((unused)), + char *buf, size_t size, off_t pos) +{ + size_t sz; + + if (pos >= (off_t)(sizeof(dummymapping) - 1)) + sz = 0; + else + if ((size + pos) >= (sizeof(dummymapping) - 1)) + sz = sizeof(dummymapping) - 1 - pos; + else + sz = size; + if (sz > 0) + memcpy(buf,&dummymapping[pos],sz); + return (sz); +} + +#endif /* POSIXACLS & SELFTESTS & !USESTUBS */ + +/* + * Build the user mapping + * - according to a mapping file if defined (or default present), + * - or try default single user mapping if possible + * + * The mapping is specific to a mounted device + * No locking done, mounting assumed non multithreaded + * + * returns zero if mapping is successful + * (failure should not be interpreted as an error) + */ + +int local_build_mapping(struct MAPPING *mapping[], const char *usermap_path) +{ +#ifdef WIN32 + char mapfile[sizeof(MAPDIR) + sizeof(MAPFILE) + 6]; +#else + char *mapfile; + char *p; +#endif + int fd; + struct MAPLIST *item; + struct MAPLIST *firstitem = (struct MAPLIST*)NULL; + struct MAPPING *usermapping; + struct MAPPING *groupmapping; + + /* be sure not to map anything until done */ + mapping[MAPUSERS] = (struct MAPPING*)NULL; + mapping[MAPGROUPS] = (struct MAPPING*)NULL; + + if (usermap_path) { +#ifdef WIN32 +/* TODO : check whether the device can store acls */ + strcpy(mapfile,"x:\\" MAPDIR "\\" MAPFILE); + if (((le16*)usermap_path)[1] == ':') + mapfile[0] = usermap_path[0]; + else + mapfile[0] = getdrive() + 'A' - 1; + fd = open(mapfile,O_RDONLY); +#else + fd = 0; + mapfile = (char*)malloc(MAXFILENAME); + if (mapfile) { + /* build a full path to locate the mapping file */ + if ((usermap_path[0] != '/') + && getcwd(mapfile,MAXFILENAME)) { + strcat(mapfile,"/"); + strcat(mapfile,usermap_path); + } else + strcpy(mapfile,usermap_path); + p = strrchr(mapfile,'/'); + if (p) + do { + strcpy(p,"/" MAPDIR "/" MAPFILE); + fd = open(mapfile,O_RDONLY); + if (fd <= 0) { + *p = 0; + p = strrchr(mapfile,'/'); + if (p == mapfile) + p = (char*)NULL; + } + } while ((fd <= 0) && p); + free(mapfile); + if (!p) { + printf("** Could not find the user mapping file\n"); + if (usermap_path[0] != '/') + printf(" Retry with full path of file\n"); + errors++; + } + } +#endif + if (fd > 0) { + firstitem = ntfs_read_mapping(basicread, (void*)&fd); + close(fd); + } + } else { +#if SELFTESTS & !USESTUBS + firstitem = ntfs_read_mapping(dummyread, (void*)NULL); +#endif + } + + if (firstitem) { + usermapping = ntfs_do_user_mapping(firstitem); + groupmapping = ntfs_do_group_mapping(firstitem); + if (usermapping && groupmapping) { + mapping[MAPUSERS] = usermapping; + mapping[MAPGROUPS] = groupmapping; + } else + ntfs_log_error("There were no valid user or no valid group\n"); + /* now we can free the memory copy of input text */ + /* and rely on internal representation */ + while (firstitem) { + item = firstitem->next; +#if USESTUBS + stdfree(firstitem); /* allocated within library */ +#else + free(firstitem); +#endif + firstitem = item; + } + } + if (mapping[MAPUSERS]) + mappingtype = MAPLOCAL; + return (!mapping[MAPUSERS]); +} + +/* + * Get an hexadecimal number (source with MSB first) + */ + +u32 getmsbhex(const char *text) +{ + u32 v; + int b; + BOOL ok; + + v = 0; + ok = TRUE; + do { + b = *text++; + if ((b >= '0') && (b <= '9')) + v = (v << 4) + b - '0'; + else + if ((b >= 'a') && (b <= 'f')) + v = (v << 4) + b - 'a' + 10; + else + if ((b >= 'A') && (b <= 'F')) + v = (v << 4) + b - 'A' + 10; + else ok = FALSE; + } while (ok); + return (v); +} + + +/* + * Get an hexadecimal number (source with LSB first) + * An odd number of digits might yield a strange result + */ + +u32 getlsbhex(const char *text) +{ + u32 v; + int b; + BOOL ok; + int pos; + + v = 0; + ok = TRUE; + pos = 0; + do { + b = *text++; + if ((b >= '0') && (b <= '9')) + v |= (u32)(b - '0') << (pos ^ 4); + else + if ((b >= 'a') && (b <= 'f')) + v |= (u32)(b - 'a' + 10) << (pos ^ 4); + else + if ((b >= 'A') && (b <= 'F')) + v |= (u32)(b - 'A' + 10) << (pos ^ 4); + else ok = FALSE; + pos += 4; + } while (ok); + return (v); +} + + +/* + * Check whether a line looks like an hex dump + */ + +BOOL ishexdump(const char *line, int first, int lth) +{ + BOOL ok; + int i; + int b; + + ok = (first >= 0) && (lth >= (first + 16)); + for (i=0; ((first+i)= '0') && (b <= '9')) + || ((b >= 'a') && (b <= 'f')) + || ((b >= 'A') && (b <= 'F')); + } + return (ok); +} + + +/* + * Display security descriptors from a file + * This is typically to convert a verbose output to a very verbose one + */ + +void showhex(FILE *fd) +{ + static char attr[MAXATTRSZ]; + char line[MAXLINE+1]; +#if POSIXACLS + struct POSIX_SECURITY *pxdesc; +#endif + int lth; + int first; + unsigned int pos; + unsigned char b; + u32 v; + int c; + int isdir; + int mode; + unsigned int off; + int i; + BOOL isdump; + BOOL done; + + b = 0; + pos = 0; + off = 0; + done = FALSE; + do { + /* input a (partial) line without displaying */ + lth = 0; + first = -1; + do { + c = getc(fd); + if ((c != ' ') && (first < 0)) + first = lth; + if (c == EOF) + done = TRUE; + else + if (c != '\r') + line[lth++] = c; + } while (!done && (c != '\n') && (lth < MAXLINE)); + /* check whether this looks like an hexadecimal dump */ + isdump = ishexdump(line, first, lth); + if (isdump) off = getmsbhex(&line[first]); + /* line is not an hexadecimal dump */ + /* display what we have in store */ + if ((!isdump || !off) && pos && ntfs_valid_descr((char*)attr,pos)) { + printf(" Computed hash : 0x%08lx\n", + (unsigned long)hash((le32*)attr, + ntfs_attr_size(attr))); + isdir = guess_dir(attr); + printf(" Estimated type : %s\n",(isdir ? "directory" : "file")); + showheader(attr,4); + showusid(attr,4); + showgsid(attr,4); + showdacl(attr,isdir,4); + showsacl(attr,isdir,4); + mode = linux_permissions(attr,isdir); + printf("Interpreted Unix mode 0%03o\n",mode); +#if POSIXACLS + /* + * Posix display not possible when user + * mapping is not available (option -h) + */ + if (mappingtype != MAPNONE) { + pxdesc = linux_permissions_posix(attr,isdir); + if (pxdesc) { + showposix(pxdesc); + free(pxdesc); + } + } +#endif + pos = 0; + } + if (isdump && !off) + pos = off; + /* line looks like an hexadecimal dump */ + /* decode it into attribute */ + if (isdump && (off == pos)) { + for (i=first+8; i 0) && (key < MAXSECURID)) { + if (!securdata[key >> SECBLKSZ]) + newblock(key); + if (securdata[key >> SECBLKSZ]) { + psecurdata = &securdata[key >> SECBLKSZ] + [key & ((1 << SECBLKSZ) - 1)]; + } + } + + /* If we have a usable attrib value. Try applying */ + badattrib = FALSE; + if (opt_e && (attrib != INVALID_FILE_ATTRIBUTES)) { +#ifdef WIN32 + badattrib = !SetFileAttributesW((LPCWSTR)fullname, attrib); +#else + badattrib = !ntfs_set_file_attributes(ntfs_context, fullname, attrib); +#endif + if (badattrib) { + printf("** Could not set Windows attrib of "); + printname(stdout,fullname); + printf(" to 0x%x\n", attrib); + printerror(stdout); + warnings++; + } + } + + if (withattr) { + if (psecurdata) { + newattr = (char*)malloc(ntfs_attr_size(attr)); + if (newattr) { + memcpy(newattr,attr,ntfs_attr_size(attr)); + psecurdata->attr = newattr; + } + } + curattr = attr; + } else + /* + * No explicit attr in backup, use attr defined + * previously for the same id + */ + if (psecurdata) + curattr = psecurdata->attr; + + + if (curattr) { + phead = (const SECURITY_DESCRIPTOR_RELATIVE*)curattr; +#ifdef WIN32 + /* SACL currently not set, need some special privilege */ + selection = OWNER_SECURITY_INFORMATION + | GROUP_SECURITY_INFORMATION + | DACL_SECURITY_INFORMATION; + bad = !SetFileSecurityW((LPCWSTR)fullname, + selection, (char*)curattr); + if (bad) + switch (GetLastError()) { + case 1307 : + case 1314 : + printf("** Could not set owner of "); + printname(stdout,fullname); + printf(", retrying with no owner setting\n"); + warnings++; + bad = !SetFileSecurityW((LPCWSTR)fullname, + selection & ~OWNER_SECURITY_INFORMATION, (char*)curattr); + break; + default : + break; + } +#else + selection = OWNER_SECURITY_INFORMATION + | GROUP_SECURITY_INFORMATION + | DACL_SECURITY_INFORMATION + | SACL_SECURITY_INFORMATION; + bad = !ntfs_set_file_security(ntfs_context,fullname, + selection, (const char*)curattr); +#endif + if (bad) { + printf("** Could not set the ACL of "); + printname(stdout,fullname); + printf("\n"); + printerror(stdout); + err = TRUE; + } else + if (opt_v) { + if (opt_e && !badattrib) + printf("ACL and attrib have been applied to "); + else + printf("ACL has been applied to "); + printname(stdout,fullname); + printf("\n"); + + } + } else { + printf("** There was no valid ACL for "); + printname(stdout,fullname); + printf("\n"); + err = TRUE; + } + return (!err); +} + +/* + * Restore security descriptors from a file + */ + +BOOL restore(FILE *fd) +{ + static char attr[MAXATTRSZ]; + char line[MAXFILENAME+25]; + char fullname[MAXFILENAME+25]; + SECURITY_DESCRIPTOR_RELATIVE *phead; + int lth; + int first; + unsigned int pos; + unsigned int size; + unsigned char b; + int c; + int isdir; + int mode; + s32 key; + BOOL isdump; + unsigned int off; + u32 v; + u32 oldhash; + int i; + int count; + int attrib; + BOOL withattr; + BOOL done; + + b = 0; + pos = 0; + size = 0; + off = 0; + done = FALSE; + withattr = FALSE; + oldhash = 0; + key = 0; + errors = 0; + count = 0; + fullname[0] = 0; + attrib = INVALID_FILE_ATTRIBUTES; + do { + /* input a (partial) line without processing */ + lth = 0; + first = -1; + do { + c = getc(fd); + if ((c != ' ') && (first < 0)) + first = lth; + if (c == EOF) + done = TRUE; + else + if (c != '\r') + line[lth++] = c; + } while (!done && (c != '\n') && (lth < (MAXFILENAME + 24))); + /* check whether this looks like an hexadecimal dump */ + isdump = ishexdump(line, first, lth); + if (isdump) off = getmsbhex(&line[first]); + /* line is not an hexadecimal dump */ + /* apply what we have in store */ + if ((!isdump || !off) && pos && ntfs_valid_descr((char*)attr,pos)) { + withattr = TRUE; + if (opt_v >= 2) { + printf(" Computed hash : 0x%08lx\n", + (unsigned long)hash((le32*)attr, + ntfs_attr_size(attr))); + isdir = guess_dir(attr); + printf(" Estimated type : %s\n",(isdir ? "directory" : "file")); + showheader(attr,4); + showusid(attr,4); + showgsid(attr,4); + showdacl(attr,isdir,4); + showsacl(attr,isdir,4); + mode = linux_permissions(attr,isdir); + printf("Interpreted Unix mode 0%03o\n",mode); + } + size = pos; + pos = 0; + } + if (isdump && !off) + pos = off; + /* line looks like an hexadecimal dump */ + /* decode it into attribute */ + if (isdump && (off == pos)) { + for (i=first+8; i 0) + && ((line[lth-1] == '\n') || (line[lth-1] == '\r'))) + line[--lth] = 0; + if (!strncmp(line,"Computed hash : 0x",18)) + oldhash = getmsbhex(&line[18]); + if (!strncmp(line,"Security key : 0x",17)) + key = getmsbhex(&line[17]); + if (!strncmp(line,"Windows attrib : 0x",19)) + attrib = getmsbhex(&line[19]); + if (done + || !strncmp(line,"File ",5) + || !strncmp(line,"Directory ",10)) { + /* + * New file or directory (or end of file) : + * apply attribute just collected + * or apply attribute defined from current key + */ + + if (withattr + && oldhash + && (hash((const le32*)attr,ntfs_attr_size(attr)) != oldhash)) { + printf("** ACL rejected, its hash is not as expected\n"); + errors++; + } else + if (fullname[0]) { + phead = (SECURITY_DESCRIPTOR_RELATIVE*)attr; + /* set the request for auto-inheritance */ + if (phead->control & SE_DACL_AUTO_INHERITED) + phead->control |= SE_DACL_AUTO_INHERIT_REQ; + if (!applyattr(fullname,attr,withattr, + attrib,key)) + errors++; + else + count++; + } + /* save current file or directory name */ + withattr = FALSE; + key = 0; + oldhash = 0; + attrib = INVALID_FILE_ATTRIBUTES; + if (!done) { +#ifdef WIN32 + if (!strncmp(line,"File ",5)) + makeutf16(fullname,&line[5]); + else + makeutf16(fullname,&line[10]); +#else + if (!strncmp(line,"File ",5)) + strcpy(fullname,&line[5]); + else + strcpy(fullname,&line[10]); +#endif + } + } + } while (!done); + printf("%d ACLs have been applied\n",count); + return (FALSE); +} + +/* + * Open the security API in rw mode for an ACL restoration + */ + +#ifdef WIN32 +#else +BOOL dorestore(const char *volume, FILE *fd) +{ + BOOL err; + + err = FALSE; + if (!getuid()) { + if (open_security_api()) { + if (open_volume(volume,MS_NONE)) { + if (restore(fd)) err = TRUE; + close_volume(volume); + } else { + fprintf(stderr,"Could not open volume %s\n",volume); + printerror(stderr); + err = TRUE; + } + close_security_api(); + } else { + fprintf(stderr,"Could not open security API\n"); + printerror(stderr); + err = TRUE; + } + } else { + fprintf(stderr,"Restore is only possible as root\n"); + err = TRUE; + } + return (err); +} +#endif /* WIN32 */ + +#if POSIXACLS & SELFTESTS & !USESTUBS + +/* + * Merge Posix ACL rights into an u32 (self test only) + * + * Result format : -----rwxrwxrwxrwxrwx---rwxrwxrwx + * U1 U2 G1 G2 M o g w + * + * Only two users (U1, U2) and two groups (G1, G2) taken into account + */ +u32 merge_rights(const struct POSIX_SECURITY *pxdesc, BOOL def) +{ + const struct POSIX_ACE *pxace; + int i; + int users; + int groups; + int first; + int last; + u32 rights; + + rights = 0; + users = 0; + groups = 0; + if (def) { + first = pxdesc->firstdef; + last = pxdesc->firstdef + pxdesc->defcnt - 1; + } else { + first = 0; + last = pxdesc->acccnt - 1; + } + pxace = pxdesc->acl.ace; + for (i=first; i<=last; i++) { + switch (pxace[i].tag) { + case POSIX_ACL_USER_OBJ : + rights |= (pxace[i].perms & 7) << 6; + break; + case POSIX_ACL_USER : + if (users < 2) + rights |= ((u32)pxace[i].perms & 7) << (24 - 3*users); + users++; + break; + case POSIX_ACL_GROUP_OBJ : + rights |= (pxace[i].perms & 7) << 3; + break; + case POSIX_ACL_GROUP : + if (groups < 2) + rights |= ((u32)pxace[i].perms & 7) << (18 - 3*groups); + groups++; + break; + case POSIX_ACL_MASK : + rights |= ((u32)pxace[i].perms & 7) << 12; + break; + case POSIX_ACL_OTHER : + rights |= (pxace[i].perms & 7); + break; + default : + break; + } + } + return (rights); +} + +void tryposix(struct POSIX_SECURITY *pxdesc) +{ + le32 owner_sid[] = /* S-1-5-21-3141592653-589793238-462843383-1016 */ + { + cpu_to_le32(0x501), cpu_to_le32(0x05000000), cpu_to_le32(21), + cpu_to_le32(AUTH1), cpu_to_le32(AUTH2), + cpu_to_le32(AUTH3), cpu_to_le32(1016) + } ; + le32 group_sid[] = /* S-1-5-21-3141592653-589793238-462843383-513 */ + { + cpu_to_le32(0x501), cpu_to_le32(0x05000000), cpu_to_le32(21), + cpu_to_le32(AUTH1), cpu_to_le32(AUTH2), + cpu_to_le32(AUTH3), cpu_to_le32(513) + } ; + + char *attr; + BOOL isdir; + mode_t mode; + struct POSIX_SECURITY *newpxdesc; + struct POSIX_SECURITY *oldpxdesc; + static char *oldattr = (char*)NULL; + + isdir = FALSE; + if (oldattr) { + oldpxdesc = linux_permissions_posix(oldattr, isdir); + newpxdesc = ntfs_merge_descr_posix(pxdesc, oldpxdesc); + if (!newpxdesc) + newpxdesc = pxdesc; + free(oldpxdesc); + if (opt_v) { + printf("merged descriptors :\n"); + showposix(newpxdesc); + } + } else + newpxdesc = pxdesc; + attr = ntfs_build_descr_posix(context.mapping,newpxdesc, + isdir,(SID*)owner_sid,(SID*)group_sid); + if (attr && ntfs_valid_descr(attr, ntfs_attr_size(attr))) { + if (opt_v) + hexdump(attr,ntfs_attr_size(attr),8); + if (opt_v >= 2) { + showheader(attr,4); + showusid(attr,4); + showgsid(attr,4); + showdacl(attr,isdir,4); + showsacl(attr,isdir,4); + mode = linux_permissions(attr,isdir); + printf("Interpreted Unix mode 0%03o\n",mode); + printf("Interpreted back Posix descriptor :\n"); + newpxdesc = linux_permissions_posix(attr,isdir); + showposix(newpxdesc); + free(newpxdesc); + } + if (oldattr) free(oldattr); + oldattr = attr; + } +} + +static BOOL same_posix(struct POSIX_SECURITY *pxdesc1, + struct POSIX_SECURITY *pxdesc2) +{ + BOOL same; + int i; + + same = pxdesc1 + && pxdesc2 + && (pxdesc1->mode == pxdesc2->mode) + && (pxdesc1->acccnt == pxdesc2->acccnt) + && (pxdesc1->defcnt == pxdesc2->defcnt) + && (pxdesc1->firstdef == pxdesc2->firstdef) + && (pxdesc1->tagsset == pxdesc2->tagsset) + && (pxdesc1->acl.version == pxdesc2->acl.version) + && (pxdesc1->acl.flags == pxdesc2->acl.flags); + i = 0; + while (same && (i < pxdesc1->acccnt)) { + same = (pxdesc1->acl.ace[i].tag == pxdesc2->acl.ace[i].tag) + && (pxdesc1->acl.ace[i].perms == pxdesc2->acl.ace[i].perms) + && (pxdesc1->acl.ace[i].id == pxdesc2->acl.ace[i].id); + i++; + } + i = pxdesc1->firstdef; + while (same && (i < pxdesc1->firstdef + pxdesc1->defcnt)) { + same = (pxdesc1->acl.ace[i].tag == pxdesc2->acl.ace[i].tag) + && (pxdesc1->acl.ace[i].perms == pxdesc2->acl.ace[i].perms) + && (pxdesc1->acl.ace[i].id == pxdesc2->acl.ace[i].id); + i++; + } + return (same); +} + +#endif /* POSIXACLS & SELFTESTS & !USESTUBS */ + +#if SELFTESTS & !USESTUBS + +/* + * Build a dummy security descriptor + * returns descriptor in allocated memory, must free() after use + */ + +static char *build_dummy_descr(BOOL isdir __attribute__((unused)), + const SID *usid, const SID *gsid, + int cnt, + /* seq of int allow, SID *sid, int flags, u32 mask */ + ...) +{ + char *attr; + int attrsz; + SECURITY_DESCRIPTOR_RELATIVE *pnhead; + ACL *pacl; + ACCESS_ALLOWED_ACE *pace; + va_list ap; + const SID *sid; + u32 umask; + le32 mask; + int flags; + BOOL allow; + int pos; + int usidsz; + int gsidsz; + int sidsz; + int aclsz; + int i; + + if (usid) + usidsz = ntfs_sid_size(usid); + else + usidsz = 0; + if (gsid) + gsidsz = ntfs_sid_size(gsid); + else + gsidsz = 0; + + + /* allocate enough space for the new security attribute */ + attrsz = sizeof(SECURITY_DESCRIPTOR_RELATIVE) /* header */ + + usidsz + gsidsz /* usid and gsid */ + + sizeof(ACL) /* acl header */ + + cnt*40; + + attr = (char*)ntfs_malloc(attrsz); + if (attr) { + /* build the main header part */ + pnhead = (SECURITY_DESCRIPTOR_RELATIVE*) attr; + pnhead->revision = SECURITY_DESCRIPTOR_REVISION; + pnhead->alignment = 0; + /* + * The flag SE_DACL_PROTECTED prevents the ACL + * to be changed in an inheritance after creation + */ + pnhead->control = SE_DACL_PRESENT | SE_DACL_PROTECTED + | SE_SELF_RELATIVE; + /* + * Windows prefers ACL first, do the same to + * get the same hash value and avoid duplication + */ + /* build the ACL header */ + pos = sizeof(SECURITY_DESCRIPTOR_RELATIVE); + pacl = (ACL*)&attr[pos]; + pacl->revision = ACL_REVISION; + pacl->alignment1 = 0; + pacl->size = cpu_to_le16(0); /* fixed later */ + pacl->ace_count = cpu_to_le16(cnt); + pacl->alignment2 = cpu_to_le16(0); + + /* enter the ACEs */ + + pos += sizeof(ACL); + aclsz = sizeof(ACL); + va_start(ap,cnt); + for (i=0; itype = (allow ? ACCESS_ALLOWED_ACE_TYPE : ACCESS_DENIED_ACE_TYPE); + pace->flags = flags; + pace->size = cpu_to_le16(sidsz + 8); + pace->mask = mask; + memcpy(&pace->sid,sid,sidsz); + aclsz += sidsz + 8; + pos += sidsz + 8; + } + va_end(ap); + + /* append usid and gsid if defined */ + /* positions of ACL, USID and GSID into header */ + pnhead->owner = cpu_to_le32(0); + pnhead->group = cpu_to_le32(0); + if (usid) { + memcpy(&attr[pos], usid, usidsz); + pnhead->owner = cpu_to_le32(pos); + } + if (gsid) { + memcpy(&attr[pos + usidsz], gsid, gsidsz); + pnhead->group = cpu_to_le32(pos + usidsz); + } + /* positions of DACL and SACL into header */ + pnhead->sacl = cpu_to_le32(0); + if (cnt) { + pacl->size = cpu_to_le16(aclsz); + pnhead->dacl = + cpu_to_le32(sizeof(SECURITY_DESCRIPTOR_RELATIVE)); + } else + pnhead->dacl = cpu_to_le32(0); + if (!ntfs_valid_descr(attr,pos+usidsz+gsidsz)) { + printf("** Bad sample descriptor\n"); + free(attr); + attr = (char*)NULL; + errors++; + } + } else + errno = ENOMEM; + return (attr); +} + +/* + * Check a few samples with special conditions + */ + +void check_samples() +{ + char *descr = (char*)NULL; + BOOL isdir = FALSE; + mode_t perms; + mode_t expect = 0; + int cnt; + u32 expectacc; + u32 expectdef; +#if POSIXACLS + u32 accrights; + u32 defrights; + mode_t mixmode; + struct POSIX_SECURITY *pxdesc; + struct POSIX_SECURITY *pxsample; + const char *txsample; +#endif + le32 owner1[] = /* S-1-5-21-1833069642-4243175381-1340018762-1003 */ + { + cpu_to_le32(0x501), cpu_to_le32(0x05000000), cpu_to_le32(21), + cpu_to_le32(1833069642), cpu_to_le32(4243175381), + cpu_to_le32(1340018762), cpu_to_le32(1003) + } ; + le32 group1[] = /* S-1-5-21-1833069642-4243175381-1340018762-513 */ + { + cpu_to_le32(0x501), cpu_to_le32(0x05000000), cpu_to_le32(21), + cpu_to_le32(1833069642), cpu_to_le32(4243175381), + cpu_to_le32(1340018762), cpu_to_le32(513) + } ; + le32 group2[] = /* S-1-5-21-1607551490-981732888-1819828000-513 */ + { + cpu_to_le32(0x501), cpu_to_le32(0x05000000), cpu_to_le32(21), + cpu_to_le32(1607551490), cpu_to_le32(981732888), + cpu_to_le32(1819828000), cpu_to_le32(513) + } ; + le32 owner3[] = /* S-1-5-21-3141592653-589793238-462843383-1016 */ + { + cpu_to_le32(0x501), cpu_to_le32(0x05000000), cpu_to_le32(21), + cpu_to_le32(AUTH1), cpu_to_le32(AUTH2), + cpu_to_le32(AUTH3), cpu_to_le32(1016) + } ; + le32 group3[] = /* S-1-5-21-3141592653-589793238-462843383-513 */ + { + cpu_to_le32(0x501), cpu_to_le32(0x05000000), cpu_to_le32(21), + cpu_to_le32(AUTH1), cpu_to_le32(AUTH2), + cpu_to_le32(AUTH3), cpu_to_le32(513) + } ; + +#if POSIXACLS + struct { + struct POSIX_SECURITY head; + struct POSIX_ACE ace[4]; + } sampletry1 = + { + { 0645, 4, 0, 4, 0x35, + { POSIX_VERSION, 0, 0 } + }, + { + { 1, 6, -1 }, + { 4, 5, -1 }, + { 16, 4, -1 }, + { 32, 5, -1 } + } + } ; + + struct { + struct POSIX_SECURITY head; + struct POSIX_ACE ace[6]; + } sampletry3 = + { + { 0100, 6, 0, 6, 0x3f, + { POSIX_VERSION, 0, 0 } + }, + { + { 1, 1, -1 }, + { 2, 3, 1000 }, + { 4, 1, -1 }, + { 8, 3, 1002 }, + { 16, 0, -1 }, + { 32, 0, -1 } + } + } ; + + struct { + struct POSIX_SECURITY head; + struct POSIX_ACE ace[8]; + } sampletry4 = + { + { 0140, 8, 0, 8, 0x3f, + { POSIX_VERSION, 0, 0 } + }, + { + { 1, 1, -1 }, + { 2, 3, 516 }, + { 2, 6, 1000 }, + { 4, 1, -1 }, + { 8, 6, 500 }, + { 8, 3, 1002 }, + { 16, 4, -1 }, + { 32, 0, -1 } + } + } ; + + struct { + struct POSIX_SECURITY head; + struct POSIX_ACE ace[6]; + } sampletry5 = + { + { 0454, 6, 0, 6, 0x3f, + { POSIX_VERSION, 0, 0 } + }, + { + { 1, 4, -1 }, + { 2, 5, 516 }, + { 4, 4, -1 }, + { 8, 6, 500 }, + { 16, 5, -1 }, + { 32, 4, -1 } + } + } ; + + struct { + struct POSIX_SECURITY head; + struct POSIX_ACE ace[8]; + } sampletry6 = + { + { 0332, 8, 0, 8, 0x3f, + { POSIX_VERSION, 0, 0 } + }, + { + { 1, 3, -1 }, + { 2, 1, 0 }, + { 2, 2, 1000 }, + { 4, 6, -1 }, + { 8, 4, 0 }, + { 8, 5, 1002 }, + { 16, 3, -1 }, + { 32, 2, -1 } + } + } ; + + struct { + struct POSIX_SECURITY head; + struct POSIX_ACE ace[4]; + } sampletry8 = + { + { 0677, 4, 0, 4, 0x35, + { POSIX_VERSION, 0, 0 } + }, + { + { 1, 6, -1 }, + { 4, 7, -1 }, + { 16, 7, -1 }, + { 32, 7, -1 } + } + } ; + +#endif /* POSIXACLS */ + + +#if POSIXACLS + for (cnt=1; cnt<=8; cnt++) { + switch (cnt) { + case 1 : + pxsample = &sampletry1.head; + txsample = "sampletry1-a"; + isdir = FALSE; + descr = ntfs_build_descr_posix(context.mapping,&sampletry1.head, + isdir, (const SID*)owner3, (const SID*)group3); + break; + case 2 : + pxsample = &sampletry1.head; + txsample = "sampletry1-b"; + isdir = FALSE; + descr = ntfs_build_descr_posix(context.mapping,&sampletry1.head, + isdir, (const SID*)adminsid, (const SID*)group3); + break; + case 3 : + isdir = FALSE; + pxsample = &sampletry3.head; + txsample = "sampletry3"; + descr = ntfs_build_descr_posix(context.mapping,pxsample, + isdir, (const SID*)group3, (const SID*)group3); + break; + case 4 : + isdir = FALSE; + pxsample = &sampletry4.head; + txsample = "sampletry4"; + descr = ntfs_build_descr_posix(context.mapping,pxsample, + isdir, (const SID*)owner3, (const SID*)group3); + break; + case 5 : + isdir = FALSE; + pxsample = &sampletry5.head; + txsample = "sampletry5"; + descr = ntfs_build_descr_posix(context.mapping,pxsample, + isdir, (const SID*)owner3, (const SID*)group3); + break; + case 6 : + isdir = FALSE; + pxsample = &sampletry6.head; + txsample = "sampletry6-a"; + descr = ntfs_build_descr_posix(context.mapping,pxsample, + isdir, (const SID*)owner3, (const SID*)group3); + break; + case 7 : + isdir = FALSE; + pxsample = &sampletry6.head; + txsample = "sampletry6-b"; + descr = ntfs_build_descr_posix(context.mapping,pxsample, + isdir, (const SID*)adminsid, (const SID*)adminsid); + break; + case 8 : + pxsample = &sampletry8.head; + txsample = "sampletry8"; + isdir = FALSE; + descr = ntfs_build_descr_posix(context.mapping,&sampletry8.head, + isdir, (const SID*)owner3, (const SID*)group3); + break; + default : + pxsample = (struct POSIX_SECURITY*)NULL; + txsample = (const char*)NULL; + } + /* check we get original back */ + if (descr) + pxdesc = linux_permissions_posix(descr, isdir); + else + pxdesc = (struct POSIX_SECURITY*)NULL; + if (!descr || !pxdesc || !same_posix(pxsample,pxdesc)) { + printf("** Error in %s\n",txsample); + showposix(pxsample); + showall(descr,0); + showposix(pxdesc); + errors++; + } + free(descr); + free(pxdesc); + } + +#endif /* POSIXACLS */ + + + /* + * Check a few samples built by Windows, + * which cannot be generated by Linux + */ + + for (cnt=1; cnt<=8; cnt++) { + switch(cnt) { + case 1 : /* hp/tmp */ + isdir = TRUE; + descr = build_dummy_descr(isdir, + (const SID*)owner1, (const SID*)group1, + 1, + (int)TRUE, worldsid, (int)0x3, (u32)0x1f01ff); + expectacc = expect = 0777; + expectdef = 0; + break; + case 2 : /* swsetup */ + isdir = TRUE; + descr = build_dummy_descr(isdir, adminsid, (const SID*)group2, + 2, + (int)TRUE, worldsid, (int)0x0, (u32)0x1f01ff, + (int)TRUE, worldsid, (int)0xb, (u32)0x1f01ff); + expectacc = expect = 0777; + expectdef = 0777; + break; + case 3 : /* Dr Watson */ + isdir = TRUE; + descr = build_dummy_descr(isdir, (const SID*)owner3, (const SID*)group3, + 0); + expectacc = expect = 0700; + expectdef = 0; + break; + case 4 : + isdir = FALSE; + descr = build_dummy_descr(isdir, + (const SID*)owner3, (const SID*)group3, + 4, + (int)TRUE, (const SID*)owner3, 0, + le32_to_cpu(FILE_READ_DATA | OWNER_RIGHTS), + (int)TRUE, (const SID*)group3, 0, + le32_to_cpu(FILE_WRITE_DATA), + (int)TRUE, (const SID*)group2, 0, + le32_to_cpu(FILE_WRITE_DATA | FILE_READ_DATA), + (int)TRUE, (const SID*)worldsid, 0, + le32_to_cpu(FILE_EXECUTE)); + expect = 0731; + expectacc = 07070731; + expectdef = 0; + break; + case 5 : /* Vista/JP */ + isdir = TRUE; + descr = build_dummy_descr(isdir, systemsid, systemsid, + 6, + (int)TRUE, owner1, (int)0x0, (u32)0x1f01ff, + (int)TRUE, systemsid, (int)0x0, (u32)0x1f01ff, + (int)TRUE, adminsid, (int)0x0, (u32)0x1f01ff, + (int)TRUE, owner1, (int)0xb, (u32)0x10000000, + (int)TRUE, systemsid, (int)0xb, (u32)0x10000000, + (int)TRUE, adminsid, (int)0xb, (u32)0x10000000); + expectacc = expect = 0700; + expectdef = 0700; + break; + case 6 : /* Vista/JP2 */ + isdir = TRUE; + descr = build_dummy_descr(isdir, systemsid, systemsid, + 7, + (int)TRUE, owner1, (int)0x0, (u32)0x1f01ff, + (int)TRUE, systemsid, (int)0x0, (u32)0x1f01ff, + (int)TRUE, adminsid, (int)0x0, (u32)0x1f01ff, + (int)TRUE, owner1, (int)0xb, (u32)0x1f01ff, + (int)TRUE, systemsid, (int)0xb, (u32)0x1f01ff, + (int)TRUE, adminsid, (int)0xb, (u32)0x1f01ff, + (int)TRUE, owner3, (int)0x3, (u32)0x1200a9); + expectacc = 0500070700; + expectdef = 0700; + expect = 0700; + break; + case 7 : /* WinXP/JP */ + isdir = TRUE; + descr = build_dummy_descr(isdir, adminsid, systemsid, + 6, + (int)TRUE, owner1, (int)0x0, (u32)0x1f01ff, + (int)TRUE, systemsid, (int)0x0, (u32)0x1f01ff, + (int)TRUE, adminsid, (int)0x0, (u32)0x1f01ff, + (int)TRUE, owner1, (int)0xb, (u32)0x10000000, + (int)TRUE, systemsid, (int)0xb, (u32)0x10000000, + (int)TRUE, adminsid, (int)0xb, (u32)0x10000000); + expectacc = expect = 0700; + expectdef = 0700; + break; + case 8 : /* WinXP/JP2 */ + isdir = TRUE; + descr = build_dummy_descr(isdir, adminsid, systemsid, + 6, + (int)TRUE, owner1, (int)0x0, (u32)0x1f01ff, + (int)TRUE, systemsid, (int)0x0, (u32)0x1f01ff, + (int)TRUE, adminsid, (int)0x0, (u32)0x1f01ff, + (int)TRUE, owner1, (int)0xb, (u32)0x10000000, + (int)TRUE, systemsid, (int)0xb, (u32)0x10000000, + (int)TRUE, adminsid, (int)0xb, (u32)0x10000000); + expectacc = expect = 0700; + expectdef = 0700; + break; + default : + expectacc = expectdef = 0; + break; + } + if (descr) { + perms = linux_permissions(descr, isdir); + if (perms != expect) { + printf("** Error in sample %d, perms 0%03o expected 0%03o\n", + cnt,perms,expect); + showall(descr,0); + errors++; + } else { +#if POSIXACLS + pxdesc = linux_permissions_posix(descr, isdir); + if (pxdesc) { + accrights = merge_rights(pxdesc,FALSE); + defrights = merge_rights(pxdesc,TRUE); + if (!(pxdesc->tagsset & ~(POSIX_ACL_USER_OBJ | POSIX_ACL_GROUP_OBJ | POSIX_ACL_OTHER))) + mixmode = expect; + else + mixmode = (expect & 07707) | ((accrights >> 9) & 070); + if ((pxdesc->mode != mixmode) + || (accrights != expectacc) + || (defrights != expectdef)) { + printf("** Error in sample %d : mode %03o expected 0%03o\n", + cnt,pxdesc->mode,mixmode); + printf(" Posix access rights 0%03lo expected 0%03lo\n", + (long)accrights,(long)expectacc); + printf(" default rights 0%03lo expected 0%03lo\n", + (long)defrights,(long)expectdef); + showall(descr,0); + showposix(pxdesc); +exit(1); + } + free(pxdesc); + } +#endif + } + free(descr); + } + } +} + + +/* + * Check whether any basic permission setting is interpreted + * back exactly as set + */ + +void basictest(int kind, BOOL isdir, const SID *owner, const SID *group) +{ + char *attr; + mode_t perm; + mode_t gotback; + u32 count; + u32 acecount; + u32 globhash; + const SECURITY_DESCRIPTOR_RELATIVE *phead; + const ACL *pacl; + enum { ERRNO, + ERRMA, ERRPA, /* error converting mode or Posix ACL to NTFS */ + ERRAM, ERRAP, /* error converting NTFS to mode or Posix ACL */ + } err; + u32 expectcnt[] = { + 27800, 31896, + 24064, 28160, + 24064, 28160, + 24064, 28160, + 25416, 29512 + } ; + u32 expecthash[] = { + 0x8f80865b, 0x7bc7960, + 0x8fd9ecfe, 0xddd4db0, + 0xa8b07400, 0xa189c20, + 0xc5689a00, 0xb6c09000, + 0x94bfb419, 0xa4311791 + } ; +#if POSIXACLS + struct POSIX_SECURITY *pxdesc; + char *pxattr; + u32 pxcount; + u32 pxacecount; + u32 pxglobhash; +#endif + + count = 0; + acecount = 0; + globhash = 0; +#if POSIXACLS + pxcount = 0; + pxacecount = 0; + pxglobhash = 0; +#endif + for (perm=0; (perm<=07777) && (errors < 10); perm++) { + err = ERRNO; + /* file owned by plain user and group */ + attr = ntfs_build_descr(perm,isdir,owner,(const SID*)group); + if (attr && ntfs_valid_descr(attr, ntfs_attr_size(attr))) { + phead = (const SECURITY_DESCRIPTOR_RELATIVE*)attr; + pacl = (const ACL*)&attr[le32_to_cpu(phead->dacl)]; + acecount += le16_to_cpu(pacl->ace_count); + globhash += hash((const le32*)attr,ntfs_attr_size(attr)); + count++; +#if POSIXACLS + /* + * Build a NTFS ACL from a mode, and + * decode to a Posix ACL, expecting to + * get the original mode back. + */ + pxdesc = linux_permissions_posix(attr, isdir); + if (!pxdesc || (pxdesc->mode != perm)) { + err = ERRAP; + if (pxdesc) + gotback = pxdesc->mode; + else + gotback = 0; + } else { + /* + * Build a NTFS ACL from the Posix ACL, expecting to + * get exactly the same NTFS ACL, then decode to a + * mode, expecting to get the original mode back. + */ + pxattr = ntfs_build_descr_posix(context.mapping, + pxdesc,isdir,owner, + (const SID*)group); + if (pxattr && !memcmp(pxattr,attr, + ntfs_attr_size(attr))) { + phead = (const SECURITY_DESCRIPTOR_RELATIVE*)attr; + pacl = (const ACL*)&attr[le32_to_cpu(phead->dacl)]; + pxacecount += le16_to_cpu(pacl->ace_count); + pxglobhash += hash((const le32*)attr,ntfs_attr_size(attr)); + pxcount++; + gotback = linux_permissions(pxattr, isdir); + if (gotback != perm) + err = ERRAM; + else + free(pxattr); + } else + err = ERRPA; + free(attr); + } + free(pxdesc); +#else + gotback = linux_permissions(attr, isdir); + if (gotback != perm) + err = ERRAM; + else + free(attr); +#endif /* POSIXACLS */ + } else + err = ERRMA; + + switch (err) { + case ERRMA : + printf("** no or wrong permission settings " + "for kind %d perm %03o\n",kind,perm); + if (attr && opt_v) + hexdump(attr,ntfs_attr_size(attr),8); + if (attr && (opt_v >= 2)) { + showheader(attr,4); + showusid(attr,4); + showgsid(attr,4); + showdacl(attr,isdir,4); + showsacl(attr,isdir,4); + } + errors++; + break; + case ERRPA : + printf("** no or wrong permission settings from PX " + "for kind %d perm %03o\n",kind,perm); + errors++; + break; +#if POSIXACLS + case ERRAM : + printf("** wrong permission settings, " + "kind %d perm 0%03o, gotback %03o\n", + kind, perm, gotback); + if (opt_v) + hexdump(pxattr,ntfs_attr_size(pxattr),8); + if (opt_v >= 2) { + showheader(pxattr,4); + showusid(pxattr,4); + showgsid(pxattr,4); + showdacl(pxattr,isdir,4); + showsacl(pxattr,isdir,4); + } + errors++; + break; + case ERRAP : + /* continued */ +#else + case ERRAM : + case ERRAP : +#endif /* POSIXACLS */ + printf("** wrong permission settings, " + "kind %d perm 0%03o, gotback %03o\n", + kind, perm, gotback); + if (opt_v) + hexdump(attr,ntfs_attr_size(attr),8); + if (opt_v >= 2) { + showheader(attr,4); + showusid(attr,4); + showgsid(attr,4); + showdacl(attr,isdir,4); + showsacl(attr,isdir,4); + } + errors++; + free(attr); + break; + default : + break; + } + } + printf("%lu ACLs built from mode, %lu ACE built, mean count %lu.%02lu\n", + (unsigned long)count,(unsigned long)acecount, + (unsigned long)acecount/count,acecount*100L/count%100L); + if (acecount != expectcnt[kind]) { + printf("** Error : expected ACE count %lu\n", + (unsigned long)expectcnt[kind]); + errors++; + } + if (globhash != expecthash[kind]) { + printf("** Error : wrong global hash 0x%lx instead of 0x%lx\n", + (unsigned long)globhash, (unsigned long)expecthash[kind]); + errors++; + } +#if POSIXACLS + printf("%lu ACLs built from Posix ACLs, %lu ACE built, mean count %lu.%02lu\n", + (unsigned long)pxcount,(unsigned long)pxacecount, + (unsigned long)pxacecount/pxcount,pxacecount*100L/pxcount%100L); + if (pxacecount != expectcnt[kind]) { + printf("** Error : expected ACE count %lu\n", + (unsigned long)expectcnt[kind]); + errors++; + } + if (pxglobhash != expecthash[kind]) { + printf("** Error : wrong global hash 0x%lx instead of 0x%lx\n", + (unsigned long)pxglobhash, (unsigned long)expecthash[kind]); + errors++; + } +#endif /* POSIXACLS */ +} + +#if POSIXACLS + +/* + * Check whether Posix ACL settings are interpreted + * back exactly as set + */ + +void posixtest(int kind, BOOL isdir, + const SID *owner, const SID *group) +{ + struct POSIX_SECURITY *pxdesc; + struct { + struct POSIX_SECURITY pxdesc; + struct POSIX_ACE aces[10]; + } desc; + int ownobj; + int grpobj; + int usr; + int grp; + int wrld; + int mask; + int mindes, maxdes; + int minmsk, maxmsk; + char *pxattr; + u32 count; + u32 acecount; + u32 globhash; + const SECURITY_DESCRIPTOR_RELATIVE *phead; + const ACL *pacl; + struct POSIX_SECURITY *gotback; + enum { ERRNO, + ERRMA, ERRPA, /* error converting mode or Posix ACL to NTFS */ + ERRAM, ERRAP, /* error converting NTFS to mode or Posix ACL */ + } err; + u32 expectcnt[] = { +#ifdef STSC + 32400, 34992, + 25920, 28512, + 25920, 28512, + 25920, 28512, + 26460, 29052, + 0, 0, + 0, 0, + 0, 0, + 24516, 27108, + 20736, 23328, + 20736, 23328, + 20736, 23328, + 21060, 23652, +#else + 252720, 273456, + 199584, 220320, + 199584, 220320, + 199584, 220320, + 203904, 224640, + 0, 0, + 0, 0, + 0, 0, + 196452, 217188, + 165888, 186624, + 165888, 186624, + 165888, 186624, + 168480, 189216, +#endif + 0, 0, + 0, 0, + 0, 0, + 16368, 18672, + 0, 0, + 13824, 0, + 0, 0, + 14640, 0 + } ; + u32 expecthash[] = { +#ifdef STSC + 0xf9f82115, 0x40666647, + 0xde826d30, 0xa181b660, + 0x952d4500, 0x8ac49450, + 0xf80acee0, 0xbd9ec6c0, + 0xfe09b868, 0xde24e84d, + 0, 0, + 0, 0, + 0, 0, + 0x2381438d, 0x3ab42dc6, + 0x7cccf6f8, 0x108ad430, + 0x5e448840, 0x83ab6c40, + 0x9b037100, 0x8f7c3b40, + 0x04a359dc, 0xa4619609, +#else + 0x1808a6cd, 0xd82f7c60, + 0x5ad29e85, 0x518c7620, + 0x188ce270, 0x7e44e590, + 0x48a64800, 0x5bdf0030, + 0x1c64aec6, 0x8b0168fa, + 0, 0, + 0, 0, + 0, 0, + 0x169fb80e, 0x382d9a59, + 0xf9c28164, 0x1855d352, + 0xf9685700, 0x44d16700, + 0x587ebe90, 0xf7c51480, + 0x2cb1b518, 0x52408df6, +#endif + 0, 0, + 0, 0, + 0, 0, + 0x905f2e38, 0xd40c22f0, + 0, 0, + 0xdd76da00, 0, + 0, 0, + 0x718e34a0, 0 + }; + + count = 0; + acecount = 0; + globhash = 0; + /* fill headers */ + pxdesc = &desc.pxdesc; + pxdesc->mode = 0; + pxdesc->defcnt = 0; + if (kind & 32) { + pxdesc->acccnt = 4; + pxdesc->firstdef = 4; + pxdesc->tagsset = 0x35; + } else { + pxdesc->acccnt = 6;; + pxdesc->firstdef = 6; + pxdesc->tagsset = 0x3f; + } + pxdesc->acl.version = POSIX_VERSION; + pxdesc->acl.flags = 0; + pxdesc->acl.filler = 0; + /* prefill aces */ + pxdesc->acl.ace[0].tag = POSIX_ACL_USER_OBJ; + pxdesc->acl.ace[0].id = -1; + if (kind & 32) { + pxdesc->acl.ace[1].tag = POSIX_ACL_GROUP_OBJ; + pxdesc->acl.ace[1].id = -1; + pxdesc->acl.ace[2].tag = POSIX_ACL_MASK; + pxdesc->acl.ace[2].id = -1; + pxdesc->acl.ace[3].tag = POSIX_ACL_OTHER; + pxdesc->acl.ace[3].id = -1; + } else { + pxdesc->acl.ace[1].tag = POSIX_ACL_USER; + pxdesc->acl.ace[1].id = (kind & 16 ? 0 : 1000); + pxdesc->acl.ace[2].tag = POSIX_ACL_GROUP_OBJ; + pxdesc->acl.ace[2].id = -1; + pxdesc->acl.ace[3].tag = POSIX_ACL_GROUP; + pxdesc->acl.ace[3].id = (kind & 16 ? 0 : 1002); + pxdesc->acl.ace[4].tag = POSIX_ACL_MASK; + pxdesc->acl.ace[4].id = -1; + pxdesc->acl.ace[5].tag = POSIX_ACL_OTHER; + pxdesc->acl.ace[5].id = -1; + } + + mindes = 3; + maxdes = (kind & 32 ? mindes : 6); +#ifdef STSC + minmsk = (kind & 32 ? 0 : 3); + maxmsk = (kind & 32 ? 7 : 3); +#else + minmsk = 0; + maxmsk = 7; +#endif + for (mask=minmsk; mask<=maxmsk; mask++) + for (ownobj=1; ownobj<7; ownobj++) + for (grpobj=1; grpobj<7; grpobj++) + for (wrld=0; wrld<8; wrld++) + for (usr=mindes; usr<=maxdes; usr++) + if (usr != 4) + for (grp=mindes; grp<=maxdes; grp++) + if (grp != 4) { + pxdesc->mode = (ownobj << 6) | (mask << 3) | wrld; + + pxdesc->acl.ace[0].perms = ownobj; + if (kind & 32) { + pxdesc->acl.ace[1].perms = grpobj; + pxdesc->acl.ace[2].perms = mask; + pxdesc->acl.ace[3].perms = wrld; + } else { + pxdesc->acl.ace[1].perms = usr; + pxdesc->acl.ace[2].perms = grpobj; + pxdesc->acl.ace[3].perms = grp; + pxdesc->acl.ace[4].perms = mask; + pxdesc->acl.ace[5].perms = wrld; + } + + err = ERRNO; + gotback = (struct POSIX_SECURITY*)NULL; + pxattr = ntfs_build_descr_posix(context.mapping, + pxdesc,isdir,owner,group); + if (pxattr && ntfs_valid_descr(pxattr, ntfs_attr_size(pxattr))) { + phead = (const SECURITY_DESCRIPTOR_RELATIVE*)pxattr; + pacl = (const ACL*)&pxattr[le32_to_cpu(phead->dacl)]; + acecount += le16_to_cpu(pacl->ace_count); + globhash += hash((const le32*)pxattr,ntfs_attr_size(pxattr)); + count++; + gotback = linux_permissions_posix(pxattr, isdir); + if (gotback) { + if (ntfs_valid_posix(gotback)) { + if (!same_posix(pxdesc,gotback)) { + printf("Non matching got back Posix ACL\n"); + printf("input ACL\n"); + showposix(pxdesc); + printf("NTFS owner\n"); + showusid(pxattr,4); + printf("NTFS group\n"); + showgsid(pxattr,4); + printf("NTFS DACL\n"); + showdacl(pxattr,isdir,4); + printf("gotback ACL\n"); + showposix(gotback); + errors++; +exit(1); + } + } else { + printf("Got back an invalid Posix ACL\n"); + errors++; + } + free(gotback); + } else { + printf("Could not get Posix ACL back\n"); + errors++; + } + + } else { + printf("NTFS ACL incorrect or not build\n"); + printf("input ACL\n"); + showposix(pxdesc); + printf("NTFS DACL\n"); + if (pxattr) + showdacl(pxattr,isdir,4); + else + printf(" (none)\n"); + if (gotback) { + printf("gotback ACL\n"); + showposix(gotback); + } else + printf("no gotback ACL\n"); + errors++; + } + if (pxattr) + free(pxattr); + } + printf("%lu ACLs built from Posix ACLs, %lu ACE built, mean count %lu.%02lu\n", + (unsigned long)count,(unsigned long)acecount, + (unsigned long)acecount/count,acecount*100L/count%100L); + if (acecount != expectcnt[kind]) { + printf("** Error ! expected ACE count %lu\n", + (unsigned long)expectcnt[kind]); + errors++; + } + if (globhash != expecthash[kind]) { + printf("** Error : wrong global hash 0x%lx instead of 0x%lx\n", + (unsigned long)globhash, (unsigned long)expecthash[kind]); + errors++; + } +} + +#endif /* POSIXACLS */ + +void selftests(void) +{ + le32 owner_sid[] = /* S-1-5-21-3141592653-589793238-462843383-1016 */ + { + cpu_to_le32(0x501), cpu_to_le32(0x05000000), cpu_to_le32(21), + cpu_to_le32(AUTH1), cpu_to_le32(AUTH2), + cpu_to_le32(AUTH3), cpu_to_le32(1016) + } ; + le32 group_sid[] = /* S-1-5-21-3141592653-589793238-462843383-513 */ + { + cpu_to_le32(0x501), cpu_to_le32(0x05000000), cpu_to_le32(21), + cpu_to_le32(AUTH1), cpu_to_le32(AUTH2), + cpu_to_le32(AUTH3), cpu_to_le32(513) + } ; +#if POSIXACLS +#ifdef STSC + unsigned char kindlist[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 16, 17, 18, 20, 22, 24, + 32, 33, 36, 40 } ; +#else + unsigned char kindlist[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 16, 17, 18, 20, 22, 24, 19, 21, 23, 25, + 32, 33, 36, 40 } ; +#endif + unsigned int k; +#endif /* POSIXACLS */ + int kind; + const SID *owner; + const SID *group; + BOOL isdir; + +#if POSIXACLS + local_build_mapping(context.mapping, (const char*)NULL); +#endif + /* first check samples */ + mappingtype = MAPDUMMY; + check_samples(); +if (errors) exit(1); + /* + * kind is oring of : + * 1 : directory + * 2 : owner is root + * 4 : group is root + * 8 : group is owner + * 16 : root is designated user/group + * 32 : mask present with no designated user/group + */ + for (kind=0; (kind<10) && (errors<10); kind++) { + isdir = kind & 1; + if (kind & 8) + owner = (const SID*)group_sid; + else + owner = (kind & 2 ? adminsid : (const SID*)owner_sid); + group = (kind & 4 ? adminsid : (const SID*)group_sid); + basictest(kind, isdir, owner, group); + } +#if POSIXACLS + for (k=0; (k= 10) + printf("** too many errors, test aborted\n"); +} +#endif /* SELFTESTS & !USESTUBS */ + +#ifdef WIN32 + +/* + * Get the security descriptor of a file (Windows version) + */ + +unsigned int getfull(char *attr, const char *fullname) +{ + static char part[MAXATTRSZ]; + BIGSID ownsid; + int xowner; + int ownersz; + u16 ownerfl; + ULONG attrsz; + ULONG partsz; + BOOL overflow; + + attrsz = 0; + partsz = 0; + overflow = FALSE; + if (GetFileSecurityW((LPCWSTR)fullname,OWNER_SECURITY_INFORMATION, + (char*)part,MAXATTRSZ,&partsz)) { + xowner = get4l(part,4); + if (xowner) { + ownerfl = get2l(part,2); + ownersz = ntfs_sid_size((SID*)&part[xowner]); + if (ownersz <= (int)sizeof(BIGSID)) + memcpy(ownsid,&part[xowner],ownersz); + else + overflow = TRUE; + } else { + ownerfl = 0; + ownersz = 0; + } + /* + * SACL : just feed in or clean + */ + if (!GetFileSecurityW((LPCWSTR)fullname,SACL_SECURITY_INFORMATION, + (char*)attr,MAXATTRSZ,&attrsz)) { + attrsz = 20; + set4l(attr,0); + attr[0] = SECURITY_DESCRIPTOR_REVISION; + set4l(&attr[12],0); + if (opt_v >= 2) + printf(" No SACL\n"); + } + /* + * append DACL and merge its flags + */ + partsz = 0; + set4l(&attr[16],0); + if (GetFileSecurityW((LPCWSTR)fullname,DACL_SECURITY_INFORMATION, + (char*)part,MAXATTRSZ,&partsz)) { + if ((attrsz + partsz - 20) <= MAXATTRSZ) { + memcpy(&attr[attrsz],&part[20],partsz-20); + set4l(&attr[16],(partsz > 20 ? attrsz : 0)); + set2l(&attr[2],get2l(attr,2) | (get2l(part,2) + & const_le16_to_cpu(SE_DACL_PROTECTED + | SE_DACL_AUTO_INHERITED + | SE_DACL_PRESENT))); + attrsz += partsz - 20; + } else + overflow = TRUE; + } else + if (partsz > MAXATTRSZ) + overflow = TRUE; + else { + if (opt_b) + printf("# No discretionary access control list\n"); + else + printf(" No discretionary access control list\n"); + warnings++; + } + + /* + * append owner and merge its flag + */ + if (xowner && !overflow) { + memcpy(&attr[attrsz],ownsid,ownersz); + set4l(&attr[4],attrsz); + set2l(&attr[2],get2l(attr,2) + | (ownerfl & const_le16_to_cpu(SE_OWNER_DEFAULTED))); + attrsz += ownersz; + } else + set4l(&attr[4],0); + /* + * append group + */ + partsz = 0; + set4l(&attr[8],0); + if (GetFileSecurityW((LPCWSTR)fullname,GROUP_SECURITY_INFORMATION, + (char*)part,MAXATTRSZ,&partsz)) { + if ((attrsz + partsz - 20) <= MAXATTRSZ) { + memcpy(&attr[attrsz],&part[20],partsz-20); + set4l(&attr[8],(partsz > 20 ? attrsz : 0)); + set2l(&attr[2],get2l(attr,2) | (get2l(part,2) + & const_le16_to_cpu(SE_GROUP_DEFAULTED))); + attrsz += partsz - 20; + } else + overflow = TRUE; + } else + if (partsz > MAXATTRSZ) + overflow = TRUE; + else { + printf("** No group SID\n"); + warnings++; + } + set2l(&attr[2],get2l(attr,2) + | const_le16_to_cpu(SE_SELF_RELATIVE)); + if (overflow) { + printf("** Descriptor was too long (> %d)\n",MAXATTRSZ); + warnings++; + attrsz = 0; + } else + if (!ntfs_valid_descr((char*)attr,attrsz)) { + printf("** Descriptor for "); + printname(stdout,fullname); + printf(" is not valid\n"); + errors++; + attrsz = 0; + } + + } else { + printf("** Could not get owner of "); + printname(stdout,fullname); + printf(", partsz %d\n",partsz); + printerror(stdout); + warnings++; + attrsz = 0; + } + return (attrsz); +} + +/* + * Update a security descriptor (Windows version) + */ + +BOOL updatefull(const char *name, DWORD flags, char *attr) +{ + BOOL bad; + + bad = !SetFileSecurityW((LPCWSTR)name, flags, attr); + if (bad + && (flags & OWNER_SECURITY_INFORMATION) + && (GetLastError() == 1307)) { + printf("** Could not set owner of "); + printname(stdout,name); + printf(", retrying with no owner setting\n"); + warnings++; + bad = !SetFileSecurityW((LPCWSTR)name, + flags & ~OWNER_SECURITY_INFORMATION, (char*)attr); + } + if (bad) { + printf("** Could not change attributes of "); + printname(stdout,name); + printf("\n"); + printerror(stdout); + errors++; + } + return (!bad); +} + +#else + +/* + * Get the security descriptor of a file (Linux version) + */ + +unsigned int getfull(char *attr, const char *fullname) +{ + static char part[MAXATTRSZ]; + BIGSID ownsid; + int xowner; + int ownersz; + u16 ownerfl; + u32 attrsz; + u32 partsz; + BOOL overflow; + + attrsz = 0; + partsz = 0; + overflow = FALSE; + if (ntfs_get_file_security(ntfs_context,fullname, + OWNER_SECURITY_INFORMATION, + (char*)part,MAXATTRSZ,&partsz)) { + xowner = get4l(part,4); + if (xowner) { + ownerfl = get2l(part,2); + ownersz = ntfs_sid_size((SID*)&part[xowner]); + if (ownersz <= (int)sizeof(BIGSID)) + memcpy(ownsid,&part[xowner],ownersz); + else + overflow = TRUE; + } else { + ownerfl = 0; + ownersz = 0; + } + /* + * SACL : just feed in or clean + */ + if (!ntfs_get_file_security(ntfs_context,fullname, + SACL_SECURITY_INFORMATION, + (char*)attr,MAXATTRSZ,&attrsz)) { + attrsz = 20; + set4l(attr,0); + attr[0] = SECURITY_DESCRIPTOR_REVISION; + set4l(&attr[12],0); + if (opt_v >= 2) + printf(" No SACL\n"); + } + /* + * append DACL and merge its flags + */ + partsz = 0; + set4l(&attr[16],0); + if (ntfs_get_file_security(ntfs_context,fullname, + DACL_SECURITY_INFORMATION, + (char*)part,MAXATTRSZ,&partsz)) { + if ((attrsz + partsz - 20) <= MAXATTRSZ) { + memcpy(&attr[attrsz],&part[20],partsz-20); + set4l(&attr[16],(partsz > 20 ? attrsz : 0)); + set2l(&attr[2],get2l(attr,2) | (get2l(part,2) + & const_le16_to_cpu(SE_DACL_PROTECTED + | SE_DACL_AUTO_INHERITED + | SE_DACL_PRESENT))); + attrsz += partsz - 20; + } else + overflow = TRUE; + } else + if (partsz > MAXATTRSZ) + overflow = TRUE; + else { + if (opt_b) + printf("# No discretionary access control list\n"); + else + printf(" No discretionary access control list\n"); + warnings++; + } + + /* + * append owner and merge its flag + */ + if (xowner && !overflow) { + memcpy(&attr[attrsz],ownsid,ownersz); + set4l(&attr[4],attrsz); + set2l(&attr[2],get2l(attr,2) + | (ownerfl & const_le16_to_cpu(SE_OWNER_DEFAULTED))); + attrsz += ownersz; + } else + set4l(&attr[4],0); + /* + * append group + */ + partsz = 0; + set4l(&attr[8],0); + if (ntfs_get_file_security(ntfs_context,fullname, + GROUP_SECURITY_INFORMATION, + (char*)part,MAXATTRSZ,&partsz)) { + if ((attrsz + partsz - 20) <= MAXATTRSZ) { + memcpy(&attr[attrsz],&part[20],partsz-20); + set4l(&attr[8],(partsz > 20 ? attrsz : 0)); + set2l(&attr[2],get2l(attr,2) | (get2l(part,2) + & const_le16_to_cpu(SE_GROUP_DEFAULTED))); + attrsz += partsz - 20; + } else + overflow = TRUE; + } else + if (partsz > MAXATTRSZ) + overflow = TRUE; + else { + printf("** No group SID\n"); + warnings++; + } + if (overflow) { + printf("** Descriptor was too long (> %d)\n",MAXATTRSZ); + warnings++; + attrsz = 0; + } else + if (!ntfs_valid_descr((char*)attr,attrsz)) { + printf("** Descriptor for %s is not valid\n",fullname); + errors++; + attrsz = 0; + } + + } else { + printf("** Could not get owner of %s\n",fullname); + warnings++; + attrsz = 0; + } + return (attrsz); +} + +/* + * Update a security descriptor (Linux version) + */ + +BOOL updatefull(const char *name, DWORD flags, char *attr) +{ + BOOL ok; + + ok = !ntfs_set_file_security(ntfs_context, name, flags, attr); + if (ok) { + printf("** Could not change attributes of %s\n",name); + printerror(stdout); + errors++; + } + return (ok); +} + + +#endif + +#if POSIXACLS + +/* + * Set all the parameters associated to a file + */ + +BOOL setfull_posix(const char *fullname, const struct POSIX_SECURITY *pxdesc, + BOOL isdir) +{ + static char attr[MAXATTRSZ]; + struct POSIX_SECURITY *oldpxdesc; + struct POSIX_SECURITY *newpxdesc; + const SECURITY_DESCRIPTOR_RELATIVE *phead; + char *newattr; + int err; + unsigned int attrsz; + int newattrsz; + const SID *usid; + const SID *gsid; +#if OWNERFROMACL + const SID *osid; +#endif + + printf("%s ",(isdir ? "Directory" : "File")); + printname(stdout,fullname); + if (pxdesc->acccnt) + printf("\n"); + else + printf(" mode 0%03o\n",pxdesc->mode); + + err = FALSE; + attrsz = getfull(attr, fullname); + if (attrsz) { + oldpxdesc = linux_permissions_posix(attr, isdir); + if (opt_v >= 2) { + printf("Posix equivalent of old ACL :\n"); + showposix(oldpxdesc); + } + if (oldpxdesc) { + if (!pxdesc->defcnt + && !(pxdesc->tagsset & + (POSIX_ACL_USER | POSIX_ACL_GROUP | POSIX_ACL_MASK))) { + if (!ntfs_merge_mode_posix(oldpxdesc,pxdesc->mode)) + newpxdesc = oldpxdesc; + else { + newpxdesc = (struct POSIX_SECURITY*)NULL; + free(oldpxdesc); + } + } else { + newpxdesc = ntfs_merge_descr_posix(pxdesc, oldpxdesc); + free(oldpxdesc); + } + if (opt_v) { + printf("New Posix ACL :\n"); + showposix(newpxdesc); + } + } else + newpxdesc = (struct POSIX_SECURITY*)NULL; + if (newpxdesc) { + phead = (const SECURITY_DESCRIPTOR_RELATIVE*)attr; + gsid = (const SID*)&attr[le32_to_cpu(phead->group)]; +#if OWNERFROMACL + osid = (const SID*)&attr[le32_to_cpu(phead->owner)]; + usid = ntfs_acl_owner((const char*)attr); + if (!ntfs_same_sid(usid,osid)) + printf("== Windows owner might change\n"); +#else + usid = (const SID*)&attr[le32_to_cpu(phead->owner)]; +#endif + newattr = ntfs_build_descr_posix(context.mapping, + newpxdesc,isdir,usid,gsid); + free(newpxdesc); + } else + newattr = (char*)NULL; + if (newattr) { + newattrsz = ntfs_attr_size(newattr); + if (opt_v) { + printf("New NTFS security descriptor\n"); + hexdump(newattr,newattrsz,4); + } + if (opt_v >= 2) { + printf("Expected hash : 0x%08lx\n", + (unsigned long)hash((le32*)newattr,ntfs_attr_size(newattr))); + showheader(newattr,0); + showusid(newattr,0); + showgsid(newattr,0); + showdacl(newattr,isdir,0); + showsacl(newattr,isdir,0); + } + +#ifdef WIN32 + /* + * avoid getting a set owner error on Windows + * owner should not be changed anyway + */ + if (!updatefull(fullname, + DACL_SECURITY_INFORMATION + | GROUP_SECURITY_INFORMATION + | OWNER_SECURITY_INFORMATION, + newattr)) +#else + if (!updatefull(fullname, + DACL_SECURITY_INFORMATION + | GROUP_SECURITY_INFORMATION + | OWNER_SECURITY_INFORMATION, + newattr)) +#endif + err = TRUE; +/* +{ +struct POSIX_SECURITY *interp; +printf("Reinterpreted new Posix :\n"); +interp = linux_permissions_posix(newattr,isdir); +showposix(interp); +free(interp); +} +*/ + free(newattr); + } else + err = TRUE; + } else + err = TRUE; + return (!err); +} + +#endif + +BOOL setfull(const char *fullname, int mode, BOOL isdir) +{ + static char attr[MAXATTRSZ]; + const SECURITY_DESCRIPTOR_RELATIVE *phead; + char *newattr; + int err; + unsigned int attrsz; + int newattrsz; + const SID *usid; + const SID *gsid; +#if OWNERFROMACL + const SID *osid; +#endif + + printf("%s ",(isdir ? "Directory" : "File")); + printname(stdout,fullname); + printf(" mode 0%03o\n",mode); + attrsz = getfull(attr, fullname); + err = FALSE; + if (attrsz) { + phead = (const SECURITY_DESCRIPTOR_RELATIVE*)attr; + gsid = (const SID*)&attr[le32_to_cpu(phead->group)]; +#if OWNERFROMACL + osid = (const SID*)&attr[le32_to_cpu(phead->owner)]; + usid = ntfs_acl_owner((const char*)attr); + if (!ntfs_same_sid(usid,osid)) + printf("== Windows owner might change\n"); +#else + usid = (const SID*)&attr[le32_to_cpu(phead->owner)]; +#endif + newattr = ntfs_build_descr(mode,isdir,usid,gsid); + if (newattr) { + newattrsz = ntfs_attr_size(newattr); + if (opt_v) { + printf("Security descriptor\n"); + hexdump(newattr,newattrsz,4); + } + if (opt_v >= 2) { + printf("Expected hash : 0x%08lx\n", + (unsigned long)hash((le32*)newattr,ntfs_attr_size(newattr))); + showheader(newattr,0); + showusid(newattr,0); + showgsid(newattr,0); + showdacl(newattr,isdir,0); + showsacl(newattr,isdir,0); + } + +#ifdef WIN32 + /* + * avoid getting a set owner error on Windows + * owner should not be changed anyway + */ + if (!updatefull(fullname, + DACL_SECURITY_INFORMATION + | GROUP_SECURITY_INFORMATION + | OWNER_SECURITY_INFORMATION, + newattr)) +#else + if (!updatefull(fullname, + DACL_SECURITY_INFORMATION + | GROUP_SECURITY_INFORMATION + | OWNER_SECURITY_INFORMATION, + newattr)) +#endif + err = TRUE; + free(newattr); + } + + } else + err = TRUE; + return (err); +} + +#ifdef WIN32 + +/* + * Check whether a directory with reparse data is a junction + * or a symbolic link + */ + +BOOL islink(const char *filename) +{ + WIN32_FIND_DATAW found; + HANDLE search; + BOOL link; + + link = FALSE; + search = FindFirstFileW((LPCWSTR)filename, &found); + if (search != INVALID_HANDLE_VALUE) { + link = (found.dwReserved0 == IO_REPARSE_TAG_MOUNT_POINT) + || (found.dwReserved0 == IO_REPARSE_TAG_SYMLINK); + FindClose(search); + } + return (link); +} + +#if POSIXACLS +BOOL iterate(RECURSE call, const char *fullname, const struct POSIX_SECURITY *pxdesc) +#else +BOOL iterate(RECURSE call, const char *fullname, mode_t mode) +#endif +{ + WIN32_FIND_DATAW found; + HANDLE search; + BOOL err; + unsigned int len; + char *filter; + char *inner; + + err = FALSE; + filter = (char*)malloc(MAXFILENAME); + inner = (char*)malloc(MAXFILENAME); + if (filter && inner) { + len = utf16len(fullname); + memcpy(filter, fullname, 2*len); + makeutf16(&filter[2*len],"\\*.*"); + search = FindFirstFileW((LPCWSTR)filter, &found); + if (search != INVALID_HANDLE_VALUE) { + do { + if (found.cFileName[0] != UNICODE('.')) { + memcpy(inner, fullname, 2*len); + inner[2*len] = '\\'; + inner[2*len+1] = 0; + memcpy(&inner[2*len+2],found.cFileName, + 2*utf16len((char*)found.cFileName)+2); + if (opt_v) + if (opt_b) + printf("#\n#\n"); + else + printf("\n\n"); + switch (call) { + case RECSHOW : + if (recurseshow(inner)) + err = TRUE; + break; +#if POSIXACLS + case RECSETPOSIX : + if (recurseset_posix(inner,pxdesc)) + err = TRUE; + break; +#else + case RECSET : + if (recurseset(inner,mode)) + err = TRUE; + break; +#endif + default : + err = TRUE; + } + } + } while (FindNextFileW(search, &found)); + FindClose(search); + } + free(filter); + free(inner); + } else { + printf("** Cannot process deeper : not enough memory\n"); + errors++; + err = TRUE; + } + return (err); +} + + + +/* + * Display all the parameters associated to a file (Windows version) + */ + +void showfull(const char *fullname, BOOL isdir) +{ + static char attr[MAXATTRSZ]; +#if POSIXACLS + struct POSIX_SECURITY *pxdesc; +#endif + ULONG attrsz; + int mode; + uid_t uid; + gid_t gid; + int attrib; + int level; + + printf("%s ",(isdir ? "Directory" : "File")); + printname(stdout,fullname); + printf("\n"); + + /* get individual parameters, as when trying to get them */ + /* all, and one (typically SACL) is missing, we get none, */ + /* and concatenate them, to be able to compute the hash code */ + + attrsz = getfull(attr, fullname); + if (attrsz) { + if (opt_v || opt_b) { + hexdump(attr,attrsz,8); + printf("Computed hash : 0x%08lx\n", + (unsigned long)hash((le32*)attr,attrsz)); + } + if (opt_v && opt_b) { + printf("# %s ",(isdir ? "Directory" : "File")); + printname(stdout,fullname); + printf(" hash 0x%lx\n", + (unsigned long)hash((le32*)attr,attrsz)); + } + attrib = GetFileAttributesW((LPCWSTR)fullname); + if (attrib == INVALID_FILE_ATTRIBUTES) { + printf("** Could not get file attrib\n"); + errors++; + } else + printf("Windows attrib : 0x%x\n",attrib); + if (ntfs_valid_descr(attr,attrsz)) { +#if POSIXACLS + pxdesc = linux_permissions_posix(attr,isdir); + if (pxdesc) + mode = pxdesc->mode; + else + mode = 0; +#else + mode = linux_permissions(attr,isdir); +#endif + if (opt_v >= 2) { + level = (opt_b ? 4 : 0); + showheader(attr,level); + showusid(attr,level); + showgsid(attr,level); + showdacl(attr,isdir,level); + showsacl(attr,isdir,level); + } + uid = linux_owner(attr); + gid = linux_group(attr); + if (opt_b) { + printf("# Interpreted Unix owner %d, group %d, mode 0%03o\n", + (int)uid,(int)gid,mode); + } else { + printf("Interpreted Unix owner %d, group %d, mode 0%03o\n", + (int)uid,(int)gid,mode); + } +#if POSIXACLS + if (pxdesc) { + if (!opt_b + && (pxdesc->defcnt + || (pxdesc->tagsset + & (POSIX_ACL_USER + | POSIX_ACL_GROUP + | POSIX_ACL_MASK)))) + showposix(pxdesc); + free(pxdesc); + } +#endif + } else + if (opt_b) + printf("# Descriptor fails sanity check\n"); + else + printf("Descriptor fails sanity check\n"); + } +} + +BOOL recurseshow(const char *fullname) +{ + int attrib; + int err; + BOOL isdir; + + err = FALSE; + attrib = GetFileAttributesW((LPCWSTR)fullname); + if (attrib != INVALID_FILE_ATTRIBUTES) { + isdir = (attrib & FILE_ATTRIBUTE_DIRECTORY) != 0; + showfull(fullname,isdir); + if (isdir + && !((attrib & FILE_ATTRIBUTE_REPARSE_POINT) + && islink(fullname))) { +#if POSIXACLS + err = iterate(RECSHOW, fullname, (struct POSIX_SECURITY*)NULL); +#else + err = iterate(RECSHOW, fullname, 0); +#endif + } + } else { + printf("** Could not access "); + printname(stdout,fullname); + printf("\n"); + printerror(stdout); + errors++; + err = TRUE; + } + return (err); +} + + +BOOL singleshow(const char *fullname) +{ + int attrib; + int err; + BOOL isdir; + + err = FALSE; + attrib = GetFileAttributesW((LPCWSTR)fullname); + if (attrib != INVALID_FILE_ATTRIBUTES) { + isdir = (attrib & FILE_ATTRIBUTE_DIRECTORY) != 0; + showfull(fullname,isdir); + } else { + printf("** Could not access "); + printname(stdout,fullname); + printf("\n"); + printerror(stdout); + errors++; + err = TRUE; + } + return (err); +} + +#if POSIXACLS + +BOOL recurseset_posix(const char *fullname, const struct POSIX_SECURITY *pxdesc) +{ + int attrib; + int err; + BOOL isdir; + + err = FALSE; + attrib = GetFileAttributesW((LPCWSTR)fullname); + if (attrib != INVALID_FILE_ATTRIBUTES) { + isdir = (attrib & FILE_ATTRIBUTE_DIRECTORY) != 0; + err = !setfull_posix(fullname,pxdesc,isdir); + if (err) { + printf("** Failed to update "); + printname(stdout,fullname); + printf("\n"); + errors++; + } else + if (isdir + && !((attrib & FILE_ATTRIBUTE_REPARSE_POINT) + && islink(fullname))) + iterate(RECSETPOSIX, fullname, pxdesc); + } else { + err = GetLastError(); + printf("** Could not access "); + printname(stdout,fullname); + printf("\n"); + printerror(stdout); + err = TRUE; + errors++; + } + return (err); +} + +#else + +BOOL recurseset(const char *fullname, int mode) +{ + int attrib; + int err; + BOOL isdir; + + err = FALSE; + attrib = GetFileAttributesW((LPCWSTR)fullname); + if (attrib != INVALID_FILE_ATTRIBUTES) { + isdir = (attrib & FILE_ATTRIBUTE_DIRECTORY) != 0; + setfull(fullname,mode,isdir); + if (isdir + && !((attrib & FILE_ATTRIBUTE_REPARSE_POINT) + && islink(fullname))) + iterate(RECSETPOSIX, fullname, mode); + } else { + err = GetLastError(); + printf("** Could not access "); + printname(stdout,fullname); + printf("\n"); + printerror(stdout); + err = TRUE; + errors++; + } + return (err); +} + +#endif + +#if POSIXACLS + +BOOL singleset_posix(const char *path, const struct POSIX_SECURITY *pxdesc) +{ + BOOL isdir; + BOOL err; + int attrib; + + err = FALSE; + attrib = GetFileAttributesW((LPCWSTR)path); + if (attrib != INVALID_FILE_ATTRIBUTES) { + isdir = (attrib & FILE_ATTRIBUTE_DIRECTORY); + err = !setfull_posix(path,pxdesc,isdir); + if (err) { + printf("** Failed to update "); + printname(stdout,path); + printf("\n"); + errors++; + } + } else { + printf("** Could not access "); + printname(stdout,path); + printf("\n"); + printerror(stdout); + errors++; + err = TRUE; + } + return (!err); +} + +#endif + +BOOL singleset(const char *path, int mode) +{ + BOOL isdir; + BOOL err; + int attrib; + + err = FALSE; + attrib = GetFileAttributesW((LPCWSTR)path); + if (attrib != INVALID_FILE_ATTRIBUTES) { + isdir = (attrib & FILE_ATTRIBUTE_DIRECTORY); + setfull(path,mode,isdir); + } else { + printf("** Could not access "); + printname(stdout,path); + printf("\n"); + printerror(stdout); + errors++; + err = TRUE; + } + return (!err); +} + +#else + +/* + * Display all the parameters associated to a file (Linux version) + */ + +void showfull(const char *fullname, BOOL isdir) +{ + static char attr[MAXATTRSZ]; + static char part[MAXATTRSZ]; +#if POSIXACLS + struct POSIX_SECURITY *pxdesc; +#endif + struct SECURITY_DATA *psecurdata; + char *newattr; + int securindex; + int mode; + int level; + int attrib; + u32 attrsz; + u32 partsz; + uid_t uid; + gid_t gid; + + if (opt_v || opt_b) + printf("%s %s\n",(isdir ? "Directory" : "File"),fullname); + + /* get individual parameters, as when trying to get them */ + /* all, and one (typically SACL) is missing, we get none */ + /* and concatenate them, to be able to compute the checksum */ + + partsz = 0; + securindex = ntfs_get_file_security(ntfs_context,fullname, + OWNER_SECURITY_INFORMATION, + (char*)part,MAXATTRSZ,&partsz); + + attrib = ntfs_get_file_attributes(ntfs_context, fullname); + if (attrib == INVALID_FILE_ATTRIBUTES) { + printf("** Could not get file attrib\n"); + errors++; + } + if ((securindex < 0) + || (securindex >= MAXSECURID) + || ((securindex > 0) + && ((!opt_r && !opt_b) + || !securdata[securindex >> SECBLKSZ] + || !securdata[securindex >> SECBLKSZ][securindex & ((1 << SECBLKSZ) - 1)].filecount))) + { + if (opt_v || opt_b) { + if ((securindex < -1) || (securindex >= MAXSECURID)) + printf("Security key : 0x%x out of range\n",securindex); + else + if (securindex == -1) + printf("Security key : none\n"); + else + printf("Security key : 0x%x\n",securindex); + } else { + printf("%s %s",(isdir ? "Directory" : "File"),fullname); + if ((securindex < -1) || (securindex >= MAXSECURID)) + printf(" : key 0x%x out of range\n",securindex); + else + if (securindex == -1) + printf(" : no key\n"); + else + printf(" : key 0x%x\n",securindex); + } + + attrsz = getfull(attr, fullname); + if (attrsz) { + psecurdata = (struct SECURITY_DATA*)NULL; + if ((securindex < MAXSECURID) && (securindex > 0)) { + if (!securdata[securindex >> SECBLKSZ]) + newblock(securindex); + if (securdata[securindex >> SECBLKSZ]) + psecurdata = &securdata[securindex >> SECBLKSZ] + [securindex & ((1 << SECBLKSZ) - 1)]; + } + if (opt_v && (opt_a || opt_b) && psecurdata) { + newattr = (char*)malloc(attrsz); + printf("# %s %s hash 0x%lx\n",(isdir ? "Directory" : "File"), + fullname, + (unsigned long)hash((le32*)attr,attrsz)); + if (newattr) { + memcpy(newattr,attr,attrsz); + psecurdata->attr = newattr; + } + } + if ((opt_v || opt_b) + && ((securindex >= MAXSECURID) + || (securindex <= 0) + || !psecurdata + || (!psecurdata->filecount + && !psecurdata->flags))) { + hexdump(attr,attrsz,8); + printf("Computed hash : 0x%08lx\n", + (unsigned long)hash((le32*)attr,attrsz)); + } + if (ntfs_valid_descr((char*)attr,attrsz)) { +#if POSIXACLS + pxdesc = linux_permissions_posix(attr,isdir); + if (pxdesc) + mode = pxdesc->mode; + else + mode = 0; +#else + mode = linux_permissions(attr,isdir); +#endif + attrib = ntfs_get_file_attributes(ntfs_context,fullname); + if (opt_v >= 2) { + level = (opt_b ? 4 : 0); + showheader(attr,level); + showusid(attr,level); + showgsid(attr,level); + showdacl(attr,isdir,level); + showsacl(attr,isdir,level); + } + if (attrib != INVALID_FILE_ATTRIBUTES) + printf("Windows attrib : 0x%x\n",attrib); + uid = linux_owner(attr); + gid = linux_group(attr); + if (opt_b) { + printf("# Interpreted Unix owner %d, group %d, mode 0%03o\n", + (int)uid,(int)gid,mode); + } else { + printf("Interpreted Unix owner %d, group %d, mode 0%03o\n", + (int)uid,(int)gid,mode); + } +#if POSIXACLS + if (pxdesc) { + if (!opt_b + && (pxdesc->defcnt + || (pxdesc->tagsset + & (POSIX_ACL_USER + | POSIX_ACL_GROUP + | POSIX_ACL_MASK)))) + showposix(pxdesc); + free(pxdesc); + } +#endif + if ((opt_r || opt_b) && (securindex < MAXSECURID) + && (securindex > 0) && psecurdata) { + psecurdata->filecount++; + psecurdata->mode = mode; + } + } else { + printf("** Descriptor fails sanity check\n"); + errors++; + } + } + } else + if (securindex > 0) { + if (securdata[securindex >> SECBLKSZ]) { + psecurdata = &securdata[securindex >> SECBLKSZ] + [securindex & ((1 << SECBLKSZ) - 1)]; + psecurdata->filecount++; + if (opt_b || opt_r) { + if (!opt_b && !opt_v) + printf("%s %s\n",(isdir ? "Directory" : "File"),fullname); + printf("Security key : 0x%x mode %03o (already displayed)\n", + securindex,psecurdata->mode); + if (attrib != INVALID_FILE_ATTRIBUTES) + printf("Windows attrib : 0x%x\n",attrib); + } else { + printf("%s %s",(isdir ? "Directory" : "File"),fullname); + printf(" : key 0x%x\n",securindex); + } + if ((opt_a || opt_b) && opt_v + && psecurdata && psecurdata->attr) { + printf("# %s %s hash 0x%lx\n",(isdir ? "Directory" : "File"), + fullname, + (unsigned long)hash((le32*)psecurdata->attr, + ntfs_attr_size(psecurdata->attr))); + } + } + } else { + if (!opt_v && !opt_b) + printf("%s %s",(isdir ? "Directory" : "File"),fullname); + printf(" (Failed)\n"); + printf("** Could not get security data of %s, partsz %d\n", + fullname,partsz); + printerror(stdout); + errors++; + } +} + +BOOL recurseshow(const char *path) +{ + struct CALLBACK dircontext; + struct LINK *current; + BOOL isdir; + BOOL err; + + err = FALSE; + dircontext.head = (struct LINK*)NULL; + dircontext.dir = path; + isdir = ntfs_read_directory(ntfs_context, path, + callback, &dircontext); + if (isdir) { + showfull(path,TRUE); + if (opt_v) { + if (opt_b) + printf("#\n#\n"); + else + printf("\n\n"); + } + while (dircontext.head) { + current = dircontext.head; + if (recurseshow(current->name)) err = TRUE; + dircontext.head = dircontext.head->next; + free(current); + } + } else + if (errno == ENOTDIR) { + showfull(path,FALSE); + if (opt_v) { + if (opt_b) + printf("#\n#\n"); + else + printf("\n\n"); + } + } else { + printf("** Could not access %s\n",path); + printerror(stdout); + errors++; + err = TRUE; + } + return (!err); +} + + +BOOL singleshow(const char *path) +{ + BOOL isdir; + BOOL err; + + err = FALSE; + isdir = ntfs_read_directory(ntfs_context, path, + callback, (struct CALLBACK*)NULL); + if (isdir || (errno == ENOTDIR)) + showfull(path,isdir); + else { + printf("** Could not access %s\n",path); + printerror(stdout); + errors++; + err = TRUE; + } + return (err); +} + +#ifdef HAVE_SETXATTR + +static ssize_t ntfs_getxattr(const char *path, const char *name, void *value, size_t size) +{ +#if defined(__APPLE__) || defined(__DARWIN__) + return getxattr(path, name, value, size, 0, 0); +#else + return getxattr(path, name, value, size); +#endif +} + +/* + * Display all the parameters associated to a mounted file + */ + +void showmounted(const char *fullname) +{ + + static char attr[MAXATTRSZ]; + struct stat st; +#if POSIXACLS + struct POSIX_SECURITY *pxdesc; +#endif + BOOL mapped; + int attrsz; + int mode; + uid_t uid; + gid_t gid; + u32 attrib; + int level; + BOOL isdir; + + if (!stat(fullname,&st)) { + isdir = S_ISDIR(st.st_mode); + printf("%s ",(isdir ? "Directory" : "File")); + printname(stdout,fullname); + printf("\n"); + + attrsz = ntfs_getxattr(fullname,"system.ntfs_acl",attr,MAXATTRSZ); + if (attrsz > 0) { + if (opt_v) { + hexdump(attr,attrsz,8); + printf("Computed hash : 0x%08lx\n", + (unsigned long)hash((le32*)attr,attrsz)); + } + if (ntfs_getxattr(fullname,"system.ntfs_attrib",&attrib,4) != 4) { + printf("** Could not get file attrib\n"); + errors++; + } else + printf("Windows attrib : 0x%x\n",(int)attrib); + if (ntfs_valid_descr(attr,attrsz)) { + mapped = !local_build_mapping(context.mapping,fullname); +#if POSIXACLS + if (mapped) { + pxdesc = linux_permissions_posix(attr,isdir); + if (pxdesc) + mode = pxdesc->mode; + else + mode = 0; + } else { + pxdesc = (struct POSIX_SECURITY*)NULL; + mode = linux_permissions(attr,isdir); + printf("No user mapping : " + "cannot display the Posix ACL\n"); + } +#else + mode = linux_permissions(attr,isdir); +#endif + if (opt_v >= 2) { + level = (opt_b ? 4 : 0); + showheader(attr,level); + showusid(attr,level); + showgsid(attr,level); + showdacl(attr,isdir,level); + showsacl(attr,isdir,level); + } + if (mapped) { + uid = linux_owner(attr); + gid = linux_group(attr); + printf("Interpreted Unix owner %d, group %d, mode 0%03o\n", + (int)uid,(int)gid,mode); + } else { + printf("Interpreted Unix mode 0%03o (owner and group are unmapped)\n", + mode); + } +#if POSIXACLS + if (pxdesc) { + if ((pxdesc->defcnt + || (pxdesc->tagsset + & (POSIX_ACL_USER + | POSIX_ACL_GROUP + | POSIX_ACL_MASK)))) + showposix(pxdesc); +#if USESTUBS + stdfree(pxdesc); /* allocated within library */ +#else + free(pxdesc); +#endif + } + if (mapped) + ntfs_free_mapping(context.mapping); +#endif + } else + printf("Descriptor fails sanity check\n"); + } else { + printf("** Could not get the NTFS ACL, check whether file is on NTFS\n"); + errors++; + } + } else + printf("%s not found\n",fullname); +} + +#else /* HAVE_SETXATTR */ + +void showmounted(const char *fullname __attribute__((unused))) +{ + fprintf(stderr,"Not possible on this configuration\n"); +} + +#endif /* HAVE_SETXATTR */ + +#if POSIXACLS + +BOOL recurseset_posix(const char *path, const struct POSIX_SECURITY *pxdesc) +{ + struct CALLBACK dircontext; + struct LINK *current; + BOOL isdir; + BOOL err; + + err = FALSE; + dircontext.head = (struct LINK*)NULL; + dircontext.dir = path; + isdir = ntfs_read_directory(ntfs_context, path, + callback, &dircontext); + if (isdir) { + err = !setfull_posix(path,pxdesc,TRUE); + if (err) { + printf("** Failed to update %s\n",path); + printerror(stdout); + errors++; + } else { + if (opt_b) + printf("#\n#\n"); + else + printf("\n\n"); + while (dircontext.head) { + current = dircontext.head; + recurseset_posix(current->name,pxdesc); + dircontext.head = dircontext.head->next; + free(current); + } + } + } else + if (errno == ENOTDIR) { + err = !setfull_posix(path,pxdesc,FALSE); + if (err) { + printf("** Failed to update %s\n",path); + printerror(stdout); + errors++; + } + } else { + printf("** Could not access %s\n",path); + printerror(stdout); + errors++; + err = TRUE; + } + return (!err); +} + +#else + +BOOL recurseset(const char *path, int mode) +{ + struct CALLBACK dircontext; + struct LINK *current; + BOOL isdir; + BOOL err; + + err = FALSE; + dircontext.head = (struct LINK*)NULL; + dircontext.dir = path; + isdir = ntfs_read_directory(ntfs_context, path, + callback, &dircontext); + if (isdir) { + setfull(path,mode,TRUE); + if (opt_b) + printf("#\n#\n"); + else + printf("\n\n"); + while (dircontext.head) { + current = dircontext.head; + recurseset(current->name,mode); + dircontext.head = dircontext.head->next; + free(current); + } + } else + if (errno == ENOTDIR) + setfull(path,mode,FALSE); + else { + printf("** Could not access %s\n",path); + printerror(stdout); + errors++; + err = TRUE; + } + return (!err); +} + +#endif + +#if POSIXACLS + +BOOL singleset_posix(const char *path, const struct POSIX_SECURITY *pxdesc) +{ + BOOL isdir; + BOOL err; + + err = FALSE; + isdir = ntfs_read_directory(ntfs_context, path, + callback, (struct CALLBACK*)NULL); + if (isdir || (errno == ENOTDIR)) { + err = !setfull_posix(path,pxdesc,isdir); + if (err) { + printf("** Failed to update %s\n",path); + printerror(stdout); + errors++; + } + } else { + printf("** Could not access %s\n",path); + printerror(stdout); + errors++; + err = TRUE; + } + return (!err); +} + +#endif + +BOOL singleset(const char *path, int mode) +{ + BOOL isdir; + BOOL err; + + err = FALSE; + isdir = ntfs_read_directory(ntfs_context, path, + callback, (struct CALLBACK*)NULL); + if (isdir || (errno == ENOTDIR)) + setfull(path,mode,isdir); + else { + printf("** Could not access %s\n",path); + printerror(stdout); + errors++; + err = TRUE; + } + return (!err); +} + +int callback(struct CALLBACK *dircontext, char *ntfsname, + int length, int type, + long long pos __attribute__((unused)), u64 mft_ref __attribute__((unused)), + unsigned int dt_type __attribute__((unused))) +{ + struct LINK *linkage; + char *name; + int newlth; + int size; + + size = utf8size(ntfsname,length); + if (dircontext + && (type != 2) /* 2 : dos name (8+3) */ + && (size > 0) /* chars convertible to utf8 */ + && ((length > 2) + || (ntfsname[0] != '.') + || (ntfsname[1] != '\0') + || ((ntfsname[2] || ntfsname[3]) + && ((ntfsname[2] != '.') || (ntfsname[3] != '\0'))))) { + linkage = (struct LINK*)malloc(sizeof(struct LINK) + + strlen(dircontext->dir) + + size + 2); + if (linkage) { + /* may find ".fuse_hidden*" files */ + /* recommendation is not to hide them, so that */ + /* the user has a clue to delete them */ + strcpy(linkage->name,dircontext->dir); + if (linkage->name[strlen(linkage->name) - 1] != '/') + strcat(linkage->name,"/"); + name = &linkage->name[strlen(linkage->name)]; + newlth = makeutf8(name,ntfsname,length); + name[newlth] = 0; + linkage->next = dircontext->head; + dircontext->head = linkage; + } + } + return (0); +} + +#endif + +#ifdef WIN32 + +/* + * Backup security descriptors in a directory tree (Windows mode) + */ + +BOOL backup(const char *root) +{ + BOOL err; + time_t now; + const char *txtime; + + now = time((time_t*)NULL); + txtime = ctime(&now); + printf("#\n# Recursive ACL collection on %s#\n",txtime); + err = recurseshow(root); + return (err); +} + +#else + +/* + * Backup security descriptors in a directory tree (Linux mode) + */ + +BOOL backup(const char *volume, const char *root) +{ + BOOL err; + int count; + int i,j; + time_t now; + const char *txtime; + + now = time((time_t*)NULL); + txtime = ctime(&now); + if (!getuid() && open_security_api()) { + if (open_volume(volume,MS_RDONLY)) { + printf("#\n# Recursive ACL collection on %s#\n",txtime); + err = recurseshow(root); + count = 0; + for (i=0; i<(MAXSECURID + (1 << SECBLKSZ) - 1)/(1 << SECBLKSZ); i++) + if (securdata[i]) + for (j=0; j<(1 << SECBLKSZ); j++) + if (securdata[i][j].filecount) { + count++; + } + printf("# %d security keys\n",count); + close_volume(volume); + } else { + fprintf(stderr,"Could not open volume %s\n",volume); + printerror(stdout); + err = TRUE; + } + close_security_api(); + } else { + if (getuid()) + fprintf(stderr,"This is only possible as root\n"); + else + fprintf(stderr,"Could not open security API\n"); + err = TRUE; + } + return (err); +} + +#endif + +#ifdef WIN32 + +/* + * List security descriptors in a directory tree (Windows mode) + */ + +BOOL listfiles(const char *root) +{ + BOOL err; + + if (opt_r) { + printf("\nRecursive file check\n"); + err = recurseshow(root); + } else + err = singleshow(root); + return (err); +} + +#else + +/* + * List security descriptors in a directory tree (Linux mode) + */ + +BOOL listfiles(const char *volume, const char *root) +{ + BOOL err; + int i,j; + int count; + + if (!getuid() && open_security_api()) { + if (open_volume(volume,MS_RDONLY)) { + if (opt_r) { + printf("\nRecursive file check\n"); + err = recurseshow(root); + printf("Summary\n"); + count = 0; + for (i=0; i<(MAXSECURID + (1 << SECBLKSZ) - 1)/(1 << SECBLKSZ); i++) + if (securdata[i]) + for (j=0; j<(1 << SECBLKSZ); j++) + if (securdata[i][j].filecount) { + printf("Key 0x%x : %d files, mode 0%03o\n", + i*(1 << SECBLKSZ)+j,securdata[i][j].filecount, + securdata[i][j].mode); + count++; + } + printf("%d security keys\n",count); + } else + err = singleshow(root); + close_volume(volume); + } else { + fprintf(stderr,"Could not open volume %s\n",volume); + printerror(stdout); + err = TRUE; + } + close_security_api(); + } else { + if (getuid()) + fprintf(stderr,"This is only possible as root\n"); + else + fprintf(stderr,"Could not open security API\n"); + err = TRUE; + } + return (err); +} + +#endif + +#ifndef WIN32 + +/* + * Check whether a SDS entry is valid + */ + +BOOL valid_sds(const char *attr, unsigned int offset, + unsigned int entrysz, unsigned int size, u32 prevkey, + BOOL second) +{ + BOOL unsane; + u32 comphash; + u32 key; + + unsane = FALSE; + if (!get4l(attr,0) && !get4l(attr,4)) { + printf("Entry at 0x%lx was deleted\n",(long)offset); + } else { + if ((ntfs_attr_size(&attr[20]) + 20) > entrysz) { + printf("** Entry is truncated (expected size %ld)\n", + (long)ntfs_attr_size(&attr[20] + 20)); + unsane = TRUE; + errors++; + } + if ((ntfs_attr_size(&attr[20]) + 20) < entrysz) { + printf("** Extra data appended to entry (expected size %ld)\n", + (long)ntfs_attr_size(&attr[20]) + 20); + warnings++; + } + if (!unsane && !ntfs_valid_descr((const char*)&attr[20],size)) { + printf("** General sanity check has failed\n"); + unsane = TRUE; + errors++; + } + if (!unsane) { + comphash = hash((const le32*)&attr[20],entrysz-20); + if ((u32)get4l(attr,0) == comphash) { + if (opt_v >= 2) + printf("Hash 0x%08lx (correct)\n", + (unsigned long)comphash); + } else { + printf("** hash 0x%08lx (computed : 0x%08lx)\n", + (unsigned long)get4l(attr,0), + (unsigned long)comphash); + unsane = TRUE; + errors++; + } + } + if (!unsane) { + if ((second ? get8l(attr,8) + 0x40000 : get8l(attr,8)) == offset) { + if (opt_v >= 2) + printf("Offset 0x%lx (correct)\n",(long)offset); + } else { + printf("** offset 0x%llx (expected : 0x%llx)\n", + (long long)get8l(attr,8), + (long long)(second ? get8l(attr,8) - 0x40000 : get8l(attr,8))); +// unsane = TRUE; + errors++; + } + } + if (!unsane) { + key = get4l(attr,4); + if (opt_v >= 2) + printf("Key 0x%x\n",(int)key); + if (key) { + if (key <= prevkey) { + printf("** Unordered key 0x%lx after 0x%lx\n", + (long)key,(long)prevkey); + unsane = TRUE; + errors++; + } + } + } + } + return (!unsane); +} + +/* + * Check whether a SDS entry is consistent with other known data + * and store current data for subsequent checks + */ + +int consist_sds(const char *attr, unsigned int offset, + unsigned int entrysz, BOOL second) +{ + int errcnt; + u32 key; + u32 comphash; + struct SECURITY_DATA *psecurdata; + + errcnt = 0; + key = get4l(attr,4); + if ((key > 0) && (key < MAXSECURID)) { + printf("Valid entry at 0x%lx for key 0x%lx\n", + (long)offset,(long)key); + if (!securdata[key >> SECBLKSZ]) + newblock(key); + if (securdata[key >> SECBLKSZ]) { + psecurdata = &securdata[key >> SECBLKSZ][key & ((1 << SECBLKSZ) - 1)]; + comphash = hash((const le32*)&attr[20],entrysz-20); + if (psecurdata->flags & INSDS1) { + if (psecurdata->hash != comphash) { + printf("** Different hash values : $SDS-1 0x%08lx $SDS-2 0x%08lx\n", + (unsigned long)psecurdata->hash, + (unsigned long)comphash); + errcnt++; + errors++; + } + if (psecurdata->offset != get8l(attr,8)) { + printf("** Different offsets : $SDS-1 0x%llx $SDS-2 0x%llx\n", + (long long)psecurdata->offset,(long long)get8l(attr,8)); + errcnt++; + errors++; + } + if (psecurdata->length != get4l(attr,16)) { + printf("** Different lengths : $SDS-1 0x%lx $SDS-2 0x%lx\n", + (long)psecurdata->length,(long)get4l(attr,16)); + errcnt++; + errors++; + } + } else { + if (second) { + printf("** Entry was not present in $SDS-1\n"); + errcnt++; + errors++; + } + psecurdata->hash = comphash; + psecurdata->offset = get8l(attr,8); + psecurdata->length = get4l(attr,16); + } + psecurdata->flags |= (second ? INSDS2 : INSDS1); + } + } else + if (key || get4l(attr,0)) { + printf("** Security_id 0x%x out of bounds\n",key); + warnings++; + } + return (errcnt); +} + + +/* + * Auditing of $SDS (Linux only) + */ + +int audit_sds(BOOL second) +{ + static char attr[MAXATTRSZ + 20]; + BOOL isdir; + BOOL done; + BOOL unsane; + u32 prevkey; + int errcnt; + int size; + unsigned int entrysz; + unsigned int entryalsz; + unsigned int offset; + int count; + int deleted; + int mode; + + if (second) + printf("\nAuditing $SDS-2\n"); + else + printf("\nAuditing $SDS-1\n"); + errcnt = 0; + offset = (second ? 0x40000 : 0); + count = 0; + deleted = 0; + done = FALSE; + prevkey = 0; + + /* get size of first record */ + + size = ntfs_read_sds(ntfs_context,(char*)attr,20,offset); + if (size != 20) { + if ((size < 0) && (errno == ENOTSUP)) + printf("** There is no $SDS-%d in this volume\n", + (second ? 2 : 1)); + else { + printf("** Could not open $SDS-%d, size %d\n", + (second ? 2 : 1),size); + errors++; + errcnt++; + } + } else + do { + entrysz = get4l(attr,16); + entryalsz = ((entrysz - 1) | 15) + 1; + if (entryalsz <= (MAXATTRSZ + 20)) { + /* read next header in anticipation, to get its size */ + size = ntfs_read_sds(ntfs_context, + (char*)&attr[20],entryalsz,offset + 20); + if (opt_v) + printf("\nAt offset 0x%lx got %lu bytes\n",(long)offset,(long)size); + } else { + printf("** Security attribute is too long (%ld bytes) - stopping\n", + (long)entryalsz); + errcnt++; + } + if ((entryalsz > (MAXATTRSZ + 20)) || (size < (int)(entrysz - 20))) + done = TRUE; + else { + if (opt_v) { + printf("Entry size %d bytes\n",entrysz); + hexdump(&attr[20],size,8); + } + + unsane = !valid_sds(attr,offset,entrysz, + size,prevkey,second); + if (!unsane) { + if (!get4l(attr,0) && !get4l(attr,4)) + deleted++; + else + count++; + errcnt += consist_sds(attr,offset, + entrysz, second); + if (opt_v >= 2) { + isdir = guess_dir(&attr[20]); + printf("Assuming %s descriptor\n",(isdir ? "directory" : "file")); + showheader(&attr[20],0); + showusid(&attr[20],0); + showgsid(&attr[20],0); + showdacl(&attr[20],isdir,0); + showsacl(&attr[20],isdir,0); + mode = linux_permissions( + &attr[20],isdir); + printf("Interpreted Unix mode 0%03o\n",mode); + } + prevkey = get4l(attr,4); + } + if (!unsane) { + memcpy(attr,&attr[entryalsz],20); + offset += entryalsz; + if (!get4l(attr,16) + || ((((offset - 1) | 0x3ffff) - offset + 1) < 20)) { + if (second) + offset = ((offset - 1) | 0x7ffff) + 0x40001; + else + offset = ((offset - 1) | 0x7ffff) + 1; + if (opt_v) + printf("Trying next SDS-%d block at offset 0x%lx\n", + (second ? 2 : 1), (long)offset); + size = ntfs_read_sds(ntfs_context, + (char*)attr,20,offset); + if (size != 20) { + if (opt_v) + printf("Assuming end of $SDS, got %d bytes\n",size); + done = TRUE; + } + } + } else { + printf("** Sanity check failed - stopping there\n"); + errcnt++; + errors++; + done = TRUE; + } + } + } while (!done); + if (count || deleted || errcnt) { + printf("%d valid and %d deleted entries in $SDS-%d\n", + count,deleted,(second ? 2 : 1)); + printf("%d errors in $SDS-%c\n",errcnt,(second ? '2' : '1')); + } + return (errcnt); +} + +/* + * Check whether a SII entry is sane + */ + +BOOL valid_sii(const char *entry, u32 prevkey) +{ + BOOL valid; + u32 key; + + valid = TRUE; + key = get4l(entry,16); + if (key <= prevkey) { + printf("** Unordered key 0x%lx after 0x%lx\n", + (long)key,(long)prevkey); + valid = FALSE; + errors++; + } + prevkey = key; + if (get2l(entry,0) != 20) { + printf("** offset %d (instead of 20)\n",(int)get2l(entry,0)); + valid = FALSE; + errors++; + } + if (get2l(entry,2) != 20) { + printf("** size %d (instead of 20)\n",(int)get2l(entry,2)); + valid = FALSE; + errors++; + } + if (get4l(entry,4) != 0) { + printf("** fill1 %d (instead of 0)\n",(int)get4l(entry,4)); + valid = FALSE; + errors++; + } + if (get2l(entry,12) & 1) { + if (get2l(entry,8) != 48) { + printf("** index size %d (instead of 48)\n",(int)get2l(entry,8)); + valid = FALSE; + errors++; + } + } else + if (get2l(entry,8) != 40) { + printf("** index size %d (instead of 40)\n",(int)get2l(entry,8)); + valid = FALSE; + errors++; + } + if (get2l(entry,10) != 4) { + printf("** index key size %d (instead of 4)\n",(int)get2l(entry,10)); + valid = FALSE; + errors++; + } + if ((get2l(entry,12) & ~3) != 0) { + printf("** flags 0x%x (instead of < 4)\n",(int)get2l(entry,12)); + valid = FALSE; + errors++; + } + if (get2l(entry,14) != 0) { + printf("** fill2 %d (instead of 0)\n",(int)get2l(entry,14)); + valid = FALSE; + errors++; + } + if (get4l(entry,24) != key) { + printf("** key 0x%x (instead of 0x%x)\n", + (int)get4l(entry,24),(int)key); + valid = FALSE; + errors++; + } + return (valid); +} + +/* + * Check whether a SII entry is consistent with other known data + */ + +int consist_sii(const char *entry) +{ + int errcnt; + u32 key; + struct SECURITY_DATA *psecurdata; + + errcnt = 0; + key = get4l(entry,16); + if ((key > 0) && (key < MAXSECURID)) { + printf("Valid entry for key 0x%lx\n",(long)key); + if (!securdata[key >> SECBLKSZ]) + newblock(key); + if (securdata[key >> SECBLKSZ]) { + psecurdata = &securdata[key >> SECBLKSZ][key & ((1 << SECBLKSZ) - 1)]; + psecurdata->flags |= INSII; + if (psecurdata->flags & (INSDS1 | INSDS2)) { + if ((u32)get4l(entry,20) != psecurdata->hash) { + printf("** hash 0x%x (instead of 0x%x)\n", + (unsigned int)get4l(entry,20), + (unsigned int)psecurdata->hash); + errors++; + } + if (get8l(entry,28) != psecurdata->offset) { + printf("** offset 0x%llx (instead of 0x%llx)\n", + (long long)get8l(entry,28), + (long long)psecurdata->offset); + errors++; + } + if (get4l(entry,36) != psecurdata->length) { + printf("** length 0x%lx (instead of %ld)\n", + (long)get4l(entry,36), + (long)psecurdata->length); + errors++; + } + } else { + printf("** Entry was not present in $SDS\n"); + errors++; + psecurdata->hash = get4l(entry,20); + psecurdata->offset = get8l(entry,28); + psecurdata->length = get4l(entry,36); + if (opt_v) { + printf(" hash 0x%x\n",(unsigned int)psecurdata->hash); + printf(" offset 0x%llx\n",(long long)psecurdata->offset); + printf(" length %ld\n",(long)psecurdata->length); + } + errcnt++; + } + } + } else { + printf("** Security_id 0x%x out of bounds\n",key); + warnings++; + } + return (errcnt); +} + + +/* + * Auditing of $SII (Linux only) + */ + +int audit_sii() +{ + char *entry; + int errcnt; + u32 prevkey; + BOOL valid; + BOOL done; + int count; + + printf("\nAuditing $SII\n"); + errcnt = 0; + count = 0; + entry = (char*)NULL; + prevkey = 0; + done = FALSE; + do { + entry = (char*)ntfs_read_sii(ntfs_context,(void*)entry); + if (entry) { + valid = valid_sii(entry,prevkey); + if (valid) { + count++; + errcnt += consist_sii(entry); + prevkey = get4l(entry,16); + } else + errcnt++; + } else + if ((errno == ENOTSUP) && !prevkey) + printf("** There is no $SII in this volume\n"); + } while (entry && !done); + if (count || errcnt) { + printf("%d valid entries in $SII\n",count); + printf("%d errors in $SII\n",errcnt); + } + return (errcnt); +} + +/* + * Check whether a SII entry is sane + */ + +BOOL valid_sdh(const char *entry, u32 prevkey, u32 prevhash) +{ + BOOL valid; + u32 key; + u32 currhash; + + valid = TRUE; + currhash = get4l(entry,16); + key = get4l(entry,20); + if ((currhash < prevhash) + || ((currhash == prevhash) && (key <= prevkey))) { + printf("** Unordered hash and key 0x%x 0x%x after 0x%x 0x%x\n", + (unsigned int)currhash,(unsigned int)key, + (unsigned int)prevhash,(unsigned int)prevkey); + valid = FALSE; + errors++; + } + if ((opt_v >= 2) && (currhash == prevhash)) + printf("Hash collision (not an error)\n"); + + if (get2l(entry,0) != 24) { + printf("** offset %d (instead of 24)\n",(int)get2l(entry,0)); + valid = FALSE; + errors++; + } + if (get2l(entry,2) != 20) { + printf("** size %d (instead of 20)\n",(int)get2l(entry,2)); + valid = FALSE; + errors++; + } + if (get4l(entry,4) != 0) { + printf("** fill1 %d (instead of 0)\n",(int)get4l(entry,4)); + valid = FALSE; + errors++; + } + if (get2l(entry,12) & 1) { + if (get2l(entry,8) != 56) { + printf("** index size %d (instead of 56)\n",(int)get2l(entry,8)); + valid = FALSE; + errors++; + } + } else + if (get2l(entry,8) != 48) { + printf("** index size %d (instead of 48)\n",(int)get2l(entry,8)); + valid = FALSE; + errors++; + } + if (get2l(entry,10) != 8) { + printf("** index key size %d (instead of 8)\n",(int)get2l(entry,10)); + valid = FALSE; + errors++; + } + if ((get2l(entry,12) & ~3) != 0) { + printf("** flags 0x%x (instead of < 4)\n",(int)get2l(entry,12)); + valid = FALSE; + errors++; + } + if (get2l(entry,14) != 0) { + printf("** fill2 %d (instead of 0)\n",(int)get2l(entry,14)); + valid = FALSE; + errors++; + } + if ((u32)get4l(entry,24) != currhash) { + printf("** hash 0x%x (instead of 0x%x)\n", + (unsigned int)get4l(entry,24),(unsigned int)currhash); + valid = FALSE; + errors++; + } + if (get4l(entry,28) != key) { + printf("** key 0x%x (instead of 0x%x)\n", + (int)get4l(entry,28),(int)key); + valid = FALSE; + errors++; + } + if (get4l(entry,44) + && (get4l(entry,44) != 0x490049)) { + printf("** fill3 0x%lx (instead of 0 or 0x490049)\n", + (long)get4l(entry,44)); + valid = FALSE; + errors++; + } + return (valid); +} + +/* + * Check whether a SDH entry is consistent with other known data + */ + +int consist_sdh(const char *entry) +{ + int errcnt; + u32 key; + struct SECURITY_DATA *psecurdata; + + errcnt = 0; + key = get4l(entry,20); + if ((key > 0) && (key < MAXSECURID)) { + printf("Valid entry for key 0x%lx\n",(long)key); + if (!securdata[key >> SECBLKSZ]) + newblock(key); + if (securdata[key >> SECBLKSZ]) { + psecurdata = &securdata[key >> SECBLKSZ][key & ((1 << SECBLKSZ) - 1)]; + psecurdata->flags |= INSDH; + if (psecurdata->flags & (INSDS1 | INSDS2 | INSII)) { + if ((u32)get4l(entry,24) != psecurdata->hash) { + printf("** hash 0x%x (instead of 0x%x)\n", + (unsigned int)get4l(entry,24), + (unsigned int)psecurdata->hash); + errors++; + } + if (get8l(entry,32) != psecurdata->offset) { + printf("** offset 0x%llx (instead of 0x%llx)\n", + (long long)get8l(entry,32), + (long long)psecurdata->offset); + errors++; + } + if (get4l(entry,40) != psecurdata->length) { + printf("** length %ld (instead of %ld)\n", + (long)get4l(entry,40), + (long)psecurdata->length); + errors++; + } + } else { + printf("** Entry was not present in $SDS nor in $SII\n"); + errors++; + psecurdata->hash = get4l(entry,24); + psecurdata->offset = get8l(entry,32); + psecurdata->length = get4l(entry,40); + if (opt_v) { + printf(" offset 0x%llx\n",(long long)psecurdata->offset); + printf(" length %ld\n",(long)psecurdata->length); + } + errcnt++; + } + } + } else { + printf("** Security_id 0x%x out of bounds\n",key); + warnings++; + } + return (errcnt); +} + +/* + * Auditing of $SDH (Linux only) + */ + +int audit_sdh() +{ + char *entry; + int errcnt; + int count; + u32 prevkey; + u32 prevhash; + BOOL valid; + BOOL done; + + printf("\nAuditing $SDH\n"); + count = 0; + errcnt = 0; + prevkey = 0; + prevhash = 0; + entry = (char*)NULL; + done = FALSE; + do { + entry = (char*)ntfs_read_sdh(ntfs_context,(void*)entry); + if (entry) { + valid = valid_sdh(entry,prevkey,prevhash); + if (valid) { + count++; + errcnt += consist_sdh(entry); + prevhash = get4l(entry,16); + prevkey = get4l(entry,20); + } else + errcnt++; + } else + if ((errno == ENOTSUP) && !prevkey) + printf("** There is no $SDH in this volume\n"); + } while (entry && !done); + if (count || errcnt) { + printf("%d valid entries in $SDH\n",count); + printf("%d errors in $SDH\n",errcnt); + } + return (errcnt); +} + +/* + * Audit summary + */ + +void audit_summary() +{ + int count; + int flags; + int cnt; + int found; + int i,j; + + count = 0; + found = 0; + if (opt_r) printf("Summary of security key use :\n"); + for (i=0; i<(MAXSECURID + (1 << SECBLKSZ) - 1)/(1 << SECBLKSZ); i++) + if (securdata[i]) + for (j=0; j<(1 << SECBLKSZ); j++) { + flags = securdata[i][j].flags & (INSDS1 + INSDS2 + INSII + INSDH); + if (flags) found++; + if (flags + && (flags != (INSDS1 + INSDS2 + INSII + INSDH))) + { + if (!count && !opt_r) + printf("\n** Keys not present in all files :\n"); + cnt = securdata[i][j].filecount; + if (opt_r) + printf("Key 0x%x used by %d %s, not in", + i*(1 << SECBLKSZ)+j,cnt, + (cnt > 1 ? "files" : "file")); + else + printf("Key 0x%x not in", i*(1 << SECBLKSZ)+j); + if (!(flags & INSDS1)) + printf(" SDS-1"); + if (!(flags & INSDS2)) + printf(" SDS-2"); + if (!(flags & INSII)) + printf(" SII"); + if (!(flags & INSDH)) + printf(" SDH"); + printf("\n"); + count++; + } else { + cnt = securdata[i][j].filecount; + if (opt_r && cnt) + printf("Key 0x%x used by %d %s\n", + i*(1 << SECBLKSZ)+j,cnt, + (cnt > 1 ? "files" : "file")); + } + } + if (found) { + if (count) + printf("%d keys not present in all lists\n",count); + else + printf("All keys are present in all lists\n"); + } +} + +/* + * Auditing (Linux only) + */ + +BOOL audit(const char *volume) +{ + BOOL err; + + err = FALSE; + if (!getuid() && open_security_api()) { + if (open_volume(volume,MS_RDONLY)) { + if (audit_sds(FALSE)) err = TRUE; + if (audit_sds(TRUE)) err = TRUE; + if (audit_sii()) err = TRUE; + if (audit_sdh()) err = TRUE; + if (opt_r) recurseshow("/"); + + audit_summary(); + close_volume(volume); + } + else { + fprintf(stderr,"Could not open volume %s\n",volume); + printerror(stdout); + err = TRUE; + } + close_security_api(); + } + else { + if (getuid()) + fprintf(stderr,"This is only possible as root\n"); + else fprintf(stderr,"Could not open security API\n"); + err = TRUE; + } + return (err); +} + +#endif + +#if POSIXACLS + +/* + * Encode a Posix ACL string + * [d:]{ugmo}:uid[:perms],... + */ + +struct POSIX_SECURITY *encode_posix_acl(const char *str) +{ + int acccnt; + int defcnt; + int i,k,l; + int c; + s32 id; + u16 perms; + u16 apermsset; + u16 dpermsset; + u16 tag; + u16 tagsset; + mode_t mode; + BOOL defacl; + BOOL dmask; + BOOL amask; + const char *p; + struct POSIX_ACL *acl; + struct POSIX_SECURITY *pxdesc; + enum { PXBEGIN, PXTAG, PXTAG1, PXID, PXID1, PXID2, + PXPERM, PXPERM1, PXPERM2, PXOCT, PXNEXT, PXEND, PXERR + } state; + + /* raw evaluation of ACE count */ + p = str; + amask = FALSE; + dmask = FALSE; + if (*p == 'd') { + acccnt = 0; + defcnt = 1; + } else { + if ((*p >= '0') && (*p <= '7')) + acccnt = 0; + else + acccnt = 1; + defcnt = 0; + } + while (*p) + if (*p++ == ',') { + if (*p == 'd') { + defcnt++; + if (p[1] && (p[2] == 'm')) + dmask = TRUE; + } else { + acccnt++; + if (*p == 'm') + amask = TRUE; + } + } + /* account for an implicit mask if none defined */ + if (acccnt && !amask) + acccnt++; + if (defcnt && !dmask) + defcnt++; + pxdesc = (struct POSIX_SECURITY*)malloc(sizeof(struct POSIX_SECURITY) + + (acccnt + defcnt)*sizeof(struct POSIX_ACE)); + if (pxdesc) { + pxdesc->acccnt = acccnt; + pxdesc->firstdef = acccnt; + pxdesc->defcnt = defcnt; + acl = &pxdesc->acl; + p = str; + state = PXBEGIN; + id = 0; + defacl = FALSE; + mode = 0; + apermsset = 0; + dpermsset = 0; + tag = 0; + perms = 0; + k = l = 0; + c = *p++; + while ((state != PXEND) && (state != PXERR)) { + switch (state) { + case PXBEGIN : + if (c == 'd') { + defacl = TRUE; + state = PXTAG1; + break; + } else + if ((c >= '0') && (c <= '7')) { + mode = c - '0'; + state = PXOCT; + break; + } + defacl = FALSE; + /* fall through */ + case PXTAG : + switch (c) { + case 'u' : + tag = POSIX_ACL_USER; + state = PXID; + break; + case 'g' : + tag = POSIX_ACL_GROUP; + state = PXID; + break; + case 'o' : + tag = POSIX_ACL_OTHER; + state = PXID; + break; + case 'm' : + tag = POSIX_ACL_MASK; + state = PXID; + break; + default : + state = PXERR; + break; + } + break; + case PXTAG1 : + if (c == ':') + state = PXTAG; + else + state = PXERR; + break; + case PXID : + if (c == ':') { + if ((tag == POSIX_ACL_OTHER) + || (tag == POSIX_ACL_MASK)) + state = PXPERM; + else + state = PXID1; + } else + state = PXERR; + break; + case PXID1 : + if ((c >= '0') && (c <= '9')) { + id = c - '0'; + state = PXID2; + } else + if (c == ':') { + id = -1; + if (tag == POSIX_ACL_USER) + tag = POSIX_ACL_USER_OBJ; + if (tag == POSIX_ACL_GROUP) + tag = POSIX_ACL_GROUP_OBJ; + state = PXPERM1; + } else + state = PXERR; + break; + case PXID2 : + if ((c >= '0') && (c <= '9')) + id = 10*id + c - '0'; + else + if (c == ':') + state = PXPERM1; + else + state = PXERR; + break; + case PXPERM : + if (c == ':') { + id = -1; + state = PXPERM1; + } else + state = PXERR; + break; + case PXPERM1 : + if ((c >= '0') && (c <= '7')) { + perms = c - '0'; + state = PXNEXT; + break; + } + state = PXPERM2; + perms = 0; + /* fall through */ + case PXPERM2 : + switch (c) { + case 'r' : + perms |= POSIX_PERM_R; + break; + case 'w' : + perms |= POSIX_PERM_W; + break; + case 'x' : + perms |= POSIX_PERM_X; + break; + case ',' : + case '\0' : + if (defacl) { + i = acccnt + l++; + dpermsset |= perms; + } else { + i = k++; + apermsset |= perms; + } + acl->ace[i].tag = tag; + acl->ace[i].perms = perms; + acl->ace[i].id = id; + if (c == '\0') + state = PXEND; + else + state = PXBEGIN; + break; + } + break; + case PXNEXT : + if (!c || (c == ',')) { + if (defacl) { + i = acccnt + l++; + dpermsset |= perms; + } else { + i = k++; + apermsset |= perms; + } + acl->ace[i].tag = tag; + acl->ace[i].perms = perms; + acl->ace[i].id = id; + if (c == '\0') + state = PXEND; + else + state = PXBEGIN; + } else + state = PXERR; + break; + case PXOCT : + if ((c >= '0') && (c <= '7')) + mode = (mode << 3) + c - '0'; + else + if (c == '\0') + state = PXEND; + else + state = PXBEGIN; + break; + default : + break; + } + c = *p++; + } + /* insert default mask if none defined */ + if (acccnt && !amask) { + i = k++; + acl->ace[i].tag = POSIX_ACL_MASK; + acl->ace[i].perms = apermsset; + acl->ace[i].id = -1; + } + if (defcnt && !dmask) { + i = acccnt + l++; + acl->ace[i].tag = POSIX_ACL_MASK; + acl->ace[i].perms = dpermsset; + acl->ace[i].id = -1; + } + /* compute the mode and tagsset */ + tagsset = 0; + for (i=0; iace[i].tag; + switch (acl->ace[i].tag) { + case POSIX_ACL_USER_OBJ : + mode |= acl->ace[i].perms << 6; + break; + case POSIX_ACL_GROUP_OBJ : + mode |= acl->ace[i].perms << 3; + break; + case POSIX_ACL_OTHER : + mode |= acl->ace[i].perms; + break; + default : + break; + } + pxdesc->mode = mode; + pxdesc->tagsset = tagsset; + pxdesc->acl.version = POSIX_VERSION; + pxdesc->acl.flags = 0; + pxdesc->acl.filler = 0; + if (state != PXERR) + ntfs_sort_posix(pxdesc); +showposix(pxdesc); + if ((state == PXERR) + || (k != acccnt) + || (l != defcnt) + || !ntfs_valid_posix(pxdesc)) { + if (~pxdesc->tagsset + & (POSIX_ACL_USER_OBJ | POSIX_ACL_GROUP_OBJ | POSIX_ACL_OTHER)) + fprintf(stderr,"User, group or other permissions missing\n"); + else + fprintf(stderr,"Bad ACL description\n"); + free(pxdesc); + pxdesc = (struct POSIX_SECURITY*)NULL; + } else + if (opt_v >= 2) { + printf("Interpreted input description :\n"); + showposix(pxdesc); + } + } else + errno = ENOMEM; + return (pxdesc); +} + +#endif /* POSIXACLS */ + + +int getoptions(int argc, char *argv[]) +{ + int xarg; + int narg; + const char *parg; + BOOL err; + + opt_a = FALSE; + opt_b = FALSE; + opt_e = FALSE; + opt_h = FALSE; +#if FORCEMASK + opt_m = FALSE; +#endif + opt_r = FALSE; + opt_s = FALSE; +#if SELFTESTS & !USESTUBS + opt_t = FALSE; +#endif + opt_v = 0; + xarg = 1; + err = FALSE; + while ((xarg < argc) && (argv[xarg][0] == '-')) { + parg = argv[xarg++]; + while (*++parg) + switch (*parg) + { +#ifndef WIN32 + case 'a' : + opt_a = TRUE; + break; +#endif + case 'b' : + opt_b = TRUE; + break; + case 'e' : + opt_e = TRUE; + break; + case 'h' : + opt_h = TRUE; + break; +#if FORCEMASK + case 'm' : + opt_m = TRUE; + break; +#endif + case 'r' : + case 'R' : + opt_r = TRUE; + break; + case 's' : + opt_s = TRUE; + break; +#if SELFTESTS & !USESTUBS + case 't' : + opt_t = TRUE; + break; +#endif + case 'v' : + opt_v++; + break; + default : + fprintf(stderr,"Invalid option -%c\n",*parg); + err = TRUE; + } + } + narg = argc - xarg; +#ifdef WIN32 + if ( ((opt_h || opt_s) && (narg > 1)) + || ((opt_r || opt_b) && ((narg < 1) || (narg > 2))) +#if SELFTESTS & !USESTUBS + || (opt_t && (narg > 0)) +#endif + || (opt_e && !opt_s) + || (!opt_h && !opt_r && !opt_b && !opt_s +#if SELFTESTS & !USESTUBS + && !opt_t +#endif + && ((narg < 1) || (narg > 2)))) + + err = TRUE; + if (err) { + xarg = 0; + fprintf(stderr,"Usage:\n"); +#if SELFTESTS & !USESTUBS + fprintf(stderr," secaudit -t\n"); + fprintf(stderr," run self-tests\n"); +#endif + fprintf(stderr," secaudit -h [file]\n"); + fprintf(stderr," display security descriptors within file\n"); + fprintf(stderr," secaudit [-v] file\n"); + fprintf(stderr," display the security parameters of file\n"); + fprintf(stderr," secaudit -r[v] directory\n"); + fprintf(stderr," display the security parameters of files in directory\n"); + fprintf(stderr," secaudit -b[v] directory\n"); + fprintf(stderr," backup the security parameters of files in directory\n"); + fprintf(stderr," secaudit -s[ev] [backupfile]\n"); + fprintf(stderr," set the security parameters as indicated in backup file\n"); + fprintf(stderr," with -e also set extra parameters (Windows attrib)\n"); + fprintf(stderr," secaudit perms file\n"); + fprintf(stderr," set the security parameters of file to perms\n"); + fprintf(stderr," secaudit -r[v] perms directory\n"); + fprintf(stderr," set the security parameters of files in directory to perms\n"); +#if POSIXACLS + fprintf(stderr," Note: perms can be an octal mode or a Posix ACL description\n"); +#else + fprintf(stderr," Note: perms is an octal mode\n"); +#endif + fprintf(stderr," -v is for verbose, -vv for very verbose\n"); + } +#else + if ( (opt_h && (narg > 1)) + || (opt_a && (narg != 1)) + || ((opt_r || opt_b || opt_s) && ((narg < 1) || (narg > 3))) +#if SELFTESTS & !USESTUBS + || (opt_t && (narg > 0)) +#endif + || (opt_e && !opt_s) + || (!opt_h && !opt_a && !opt_r && !opt_b && !opt_s +#if SELFTESTS & !USESTUBS + && !opt_t +#endif +#ifdef HAVE_SETXATTR + && ((narg < 1) || (narg > 3)))) +#else + && ((narg < 2) || (narg > 3)))) +#endif + err = TRUE; + if (err) { + xarg = 0; + fprintf(stderr,"Usage:\n"); +#if SELFTESTS & !USESTUBS + fprintf(stderr," secaudit -t\n"); + fprintf(stderr," run self-tests\n"); +#endif + fprintf(stderr," secaudit -h [file]\n"); + fprintf(stderr," display security descriptors within file\n"); + fprintf(stderr," secaudit -a[rv] volume\n"); + fprintf(stderr," audit the volume\n"); + fprintf(stderr," secaudit [-v] volume file\n"); + fprintf(stderr," display the security parameters of file\n"); + fprintf(stderr," secaudit -r[v] volume directory\n"); + fprintf(stderr," display the security parameters of files in directory\n"); + fprintf(stderr," secaudit -b[v] volume directory\n"); + fprintf(stderr," backup the security parameters of files in directory\n"); + fprintf(stderr," secaudit -s[ev] volume [backupfile]\n"); + fprintf(stderr," set the security parameters as indicated in backup file\n"); + fprintf(stderr," with -e also set extra parameters (Windows attrib)\n"); + fprintf(stderr," secaudit volume perms file\n"); + fprintf(stderr," set the security parameters of file to perms\n"); + fprintf(stderr," secaudit -r[v] volume perms directory\n"); + fprintf(stderr," set the security parameters of files in directory to perms\n"); +#ifdef HAVE_SETXATTR + fprintf(stderr," special case, does not require being root :\n"); + fprintf(stderr," secaudit [-v] mounted-file\n"); + fprintf(stderr," display the security parameters of a mounted file\n"); +#endif +#if POSIXACLS + fprintf(stderr," Note: perms can be an octal mode or a Posix ACL description\n"); +#else + fprintf(stderr," Note: perms is an octal mode\n"); +#endif + fprintf(stderr," -v is for verbose, -vv for very verbose\n"); + } +#endif + if ((sizeof(SID) != 12) && !err) { + fprintf(stderr,"Possible alignment problem, check your compiler options\n"); + err = TRUE; + xarg = 0; + } + return (xarg); +} + +/* + * Memory allocation with checks + */ + +#undef malloc +#undef calloc +#undef free +#undef isalloc + +void dumpalloc(const char *txt) +{ + struct CHKALLOC *q; + + if (firstalloc) { + printf("alloc table at %s\n",txt); + for (q=firstalloc; q; q=q->next) + printf("%08lx : %u bytes at %08lx allocated at %s line %d\n", + (long)q,(unsigned int)q->size, + (long)q->alloc,q->file,q->line); + } +} + +void *chkmalloc(size_t size, const char *file, int line) +{ + void *p; + struct CHKALLOC *q; + + p = (void*)malloc(size+1); + if (p) { + ((unsigned char*)p)[size] = 0xaa; + q = (struct CHKALLOC*)malloc(sizeof(struct CHKALLOC)); + if (q) { + q->next = firstalloc; + q->alloc = p; + q->size = size; + q->file = file; + q->line = line; + firstalloc = q; + } + } + return (p); +} + +void *chkcalloc(size_t cnt, size_t size, const char *file, int line) +{ + return (chkmalloc(cnt*size,file,line)); +} + +void chkfree(void *p, const char *file, int line) +{ + struct CHKALLOC *q; + struct CHKALLOC *r; + + if (p) { + if (firstalloc && (firstalloc->alloc == p)) { + r = firstalloc; + firstalloc = firstalloc->next; + } else { + q = firstalloc; + if (q) + while (q->next && (q->next->alloc != p)) + q = q->next; + if (q && q->next) { + r = q->next; + q->next = r->next; + } else { + r = (struct CHKALLOC*)NULL; + printf("** freeing unallocated memory in %s line %d\n",file,line); + if (!isatty(1)) + fprintf(stderr,"** freeing unallocated memory in %s line %d\n",file,line); + } + } + if (r) { + if (((unsigned char*)p)[r->size] != 0xaa) { + printf("** memory corruption, alloc in %s line %d release in %s %d\n", + r->file,r->line,file,line); + if (!isatty(1)) + fprintf(stderr,"** memory corruption, alloc in %s line %d release in %s %d\n", + r->file,r->line,file,line); + } + memset(p,0xaa,r->size); + free(r); + free(p); + } + } +} + +void stdfree(void *p) +{ + free(p); +} + +BOOL chkisalloc(void *p, const char *file, int line) +{ + struct CHKALLOC *q; + + if (p) { + q = firstalloc; + while (q && (q->alloc != p)) + q = q->next; + } else + q = (struct CHKALLOC*)NULL; + if (!p || !q) { + printf("error in %s %d : 0x%lx not allocated\n",file,line,(long)p); + } + return (p && q); +} + + + + +#ifdef WIN32 + +/* + * Windows version + */ + +main(argc,argv) +int argc; +char *argv[]; +{ + FILE *fd; + int xarg; + int mode; + unsigned int size; + BOOL cmderr; + char *filename; + const char *p; + int i; +#if POSIXACLS + struct POSIX_SECURITY *pxdesc; +#endif + + printf("%s\n",BANNER); + cmderr = FALSE; + errors = 0; + warnings = 0; + xarg = getoptions(argc,argv); + if (xarg) { + for (i=0; i<(MAXSECURID + (1 << SECBLKSZ) - 1)/(1 << SECBLKSZ); i++) + securdata[i] = (struct SECURITY_DATA*)NULL; +#if POSIXACLS + context.mapping[MAPUSERS] = (struct MAPPING*)NULL; + context.mapping[MAPGROUPS] = (struct MAPPING*)NULL; +#endif + firstalloc = (struct CHKALLOC*)NULL; + mappingtype = MAPNONE; + switch (argc - xarg) { + case 0 : + if (opt_h) + showhex(stdin); + else + if (opt_s) + restore(stdin); +#if SELFTESTS & !USESTUBS + if (opt_t) + selftests(); +#endif + break; + case 1 : + if (opt_h || opt_s) { + fd = fopen(argv[xarg],"r"); + if (fd) { + if (opt_h) + showhex(fd); + else + restore(fd); + fclose(fd); + } else { + fprintf(stderr,"Could not open %s\n",argv[xarg]); + cmderr = TRUE; + } + } else { + size = utf16size(argv[xarg]); + if (size) { + filename = (char*)malloc(2*size + 2); + if (filename) { + makeutf16(filename,argv[xarg]); +#if POSIXACLS + if (local_build_mapping(context.mapping,filename)) { + printf("*** Could not get user mapping data\n"); + warnings++; + } +#endif + if (opt_b) + cmderr = backup(filename); + else { + if (opt_r) + cmderr = listfiles(filename); + else + cmderr = singleshow(filename); + } +#if POSIXACLS + ntfs_free_mapping(context.mapping); +#endif + free(filename); + } else { + fprintf(stderr,"No more memory\n"); + cmderr = TRUE; + } + } else { + fprintf(stderr,"Bad UTF-8 name \"%s\"\n",argv[xarg]); + cmderr = TRUE; + } + } + break; + case 2 : + mode = 0; + p = argv[xarg]; +#if POSIXACLS + pxdesc = encode_posix_acl(p); + if (pxdesc) { + size = utf16size(argv[xarg + 1]); + if (size) { + filename = (char*)malloc(2*size + 2); + if (filename) { + makeutf16(filename,argv[xarg + 1]); + if (local_build_mapping(context.mapping,filename)) { + printf("*** Could not get user mapping data\n"); + warnings++; + } + if (opt_r) { + for (i=0; i<(MAXSECURID + (1 << SECBLKSZ) - 1)/(1 << SECBLKSZ); i++) + securdata[i] = (struct SECURITY_DATA*)NULL; + recurseset_posix(filename,pxdesc); + } else + singleset_posix(filename,pxdesc); + ntfs_free_mapping(context.mapping); + free(filename); + } else { + fprintf(stderr,"No more memory\n"); + cmderr = TRUE; + } + chkfree(pxdesc,__FILE__,__LINE__); + } else { + fprintf(stderr,"Bad UTF-8 name \"%s\"\n",argv[xarg + 1]); + cmderr = TRUE; + } + } +#else + while ((*p >= '0') && (*p <= '7')) + mode = (mode << 3) + (*p++) - '0'; + if (*p) { + fprintf(stderr,"New mode should be given in octal\n"); + cmderr = TRUE; + } else { + size = utf16size(argv[xarg + 1]); + if (size) { + filename = (char*)malloc(2*size + 2); + if (filename) { + makeutf16(filename,argv[xarg + 1]); +#if POSIXACLS + if (local_build_mapping(&context,filename)) { + printf("*** Could not get user mapping data\n"); + warnings++; + } +#endif + if (opt_r) { + for (i=0; i<(MAXSECURID + (1 << SECBLKSZ) - 1)/(1 << SECBLKSZ); i++) + securdata[i] = (struct SECURITY_DATA*)NULL; + recurseset(filename,mode); + } else + singleset(filename,mode); + free(filename); + } else { + fprintf(stderr,"No more memory\n"); + cmderr = TRUE; + } + } else { + fprintf(stderr,"Bad UTF-8 name \"%s\"\n",argv[xarg + 1]); + cmderr = TRUE; + } + } +#endif + break; +#if FORCEMASK + case 3 : + mode = 0; + forcemsk = 0; + p = argv[xarg]; + while (*p) { + if ((*p >= '0') && (*p <= '9')) + forcemsk = (forcemsk << 4) + *p - '0'; + else forcemsk = (forcemsk << 4) + (*p & 7) + 9; + p++; + } + p = argv[xarg + 1]; + while ((*p >= '0') && (*p <= '7')) + mode = (mode << 3) + (*p++) - '0'; + if (*p) { + fprintf(stderr,"New mode should be given in octal\n"); + cmderr = TRUE; + } else { + if (opt_r) { + recurseset(argv[xarg + 2],mode); + } + else singleset(argv[xarg + 2],mode); + } + break; +#endif + } + if (warnings) + printf("** %u %s signalled\n",warnings, + (warnings > 1 ? "warnings were" : "warning was")); + if (errors) + printf("** %u %s found\n",errors, + (errors > 1 ? "errors were" : "error was")); + else + printf("No errors were found\n"); + if (!isatty(1)) { + fflush(stdout); + if (warnings) + fprintf(stderr,"** %u %s signalled\n",warnings, + (warnings > 1 ? "warnings were" : "warning was")); + if (errors) + fprintf(stderr,"** %u %s found\n",errors, + (errors > 1 ? "errors were" : "error was")); + else + fprintf(stderr,"No errors were found\n"); + freeblocks(); + } + } + dumpalloc("termination"); + if (cmderr || errors) + exit(1); + return (0); +} + +#else + +/* + * Linux version + */ + +int main(int argc, char *argv[]) +{ + FILE *fd; + unsigned int mode; + const char *p; + int xarg; + BOOL cmderr; + int i; +#if POSIXACLS + struct POSIX_SECURITY *pxdesc; +#endif + + printf("%s\n",BANNER); + cmderr = FALSE; + errors = 0; + warnings = 0; + xarg = getoptions(argc,argv); + if (xarg) { + for (i=0; i<(MAXSECURID + (1 << SECBLKSZ) - 1)/(1 << SECBLKSZ); i++) + securdata[i] = (struct SECURITY_DATA*)NULL; +#if POSIXACLS + context.mapping[MAPUSERS] = (struct MAPPING*)NULL; + context.mapping[MAPGROUPS] = (struct MAPPING*)NULL; +#endif + firstalloc = (struct CHKALLOC*)NULL; + mappingtype = MAPNONE; + switch (argc - xarg) { + case 0 : + if (opt_h) + showhex(stdin); +#if SELFTESTS & !USESTUBS + if (opt_t) + selftests(); +#endif + break; + case 1 : + if (opt_a) + cmderr = audit(argv[xarg]); + else + if (opt_h) { + fd = fopen(argv[xarg],"rb"); + if (fd) { + showhex(fd); + fclose(fd); + } else { + fprintf(stderr,"Could not open %s\n",argv[xarg]); + cmderr = TRUE; + } + } else + if (opt_b) + cmderr = backup(argv[xarg],"/"); + else + if (opt_r) + cmderr = listfiles(argv[xarg],"/"); + else + if (opt_s) + cmderr = dorestore(argv[xarg],stdin); + else + showmounted(argv[xarg]); + break; + case 2 : + if (opt_b) + cmderr = backup(argv[xarg],argv[xarg+1]); + else + if (opt_s) { + fd = fopen(argv[xarg+1],"rb"); + if (fd) { + if (dorestore(argv[xarg],fd)) + cmderr = TRUE; + fclose(fd); + } else { + fprintf(stderr,"Could not open %s\n",argv[xarg]); + cmderr = TRUE; + } + } else + cmderr = listfiles(argv[xarg],argv[xarg+1]); + break; + case 3 : + mode = 0; + p = argv[xarg+1]; +#if POSIXACLS + pxdesc = encode_posix_acl(p); + if (pxdesc) { + if (!getuid() && open_security_api()) { + if (open_volume(argv[xarg],MS_NONE)) { + if (opt_r) { + for (i=0; i<(MAXSECURID + (1 << SECBLKSZ) - 1)/(1 << SECBLKSZ); i++) + securdata[i] = (struct SECURITY_DATA*)NULL; + recurseset_posix(argv[xarg + 2],pxdesc); + } else + singleset_posix(argv[xarg + 2],pxdesc); + close_volume(argv[xarg]); + } else { + fprintf(stderr,"Could not open volume %s\n",argv[xarg]); + printerror(stderr); + cmderr = TRUE; + } + close_security_api(); + } else { + if (getuid()) + fprintf(stderr,"This is only possible as root\n"); + else + fprintf(stderr,"Could not open security API\n"); + cmderr = TRUE; + } + chkfree(pxdesc,__FILE__,__LINE__); + } else + cmderr = TRUE; +#else + while ((*p >= '0') && (*p <= '7')) + mode = (mode << 3) + (*p++) - '0'; + if (*p) { + fprintf(stderr,"New mode should be given in octal\n"); + cmderr = TRUE; + } else + if (!getuid() && open_security_api()) { + if (open_volume(argv[xarg],MS_NONE)) { + if (opt_r) { + for (i=0; i<(MAXSECURID + (1 << SECBLKSZ) - 1)/(1 << SECBLKSZ); i++) + securdata[i] = (struct SECURITY_DATA*)NULL; + recurseset(argv[xarg + 2],mode); + } else + singleset(argv[xarg + 2],mode); + close_volume(argv[xarg]); + } else { + fprintf(stderr,"Could not open volume %s\n",argv[xarg]); + printerror(stderr); + cmderr = TRUE; + } + close_security_api(); + } else { + if (getuid()) + fprintf(stderr,"This is only possible as root\n"); + else + fprintf(stderr,"Could not open security API\n"); + cmderr = TRUE; + } +#endif + break; + } + if (warnings) + printf("** %u %s signalled\n",warnings, + (warnings > 1 ? "warnings were" : "warning was")); + if (errors) + printf("** %u %s found\n",errors, + (errors > 1 ? "errors were" : "error was")); + else + if (!cmderr) + printf("No errors were found\n"); + if (!isatty(1)) { + fflush(stdout); + if (warnings) + fprintf(stderr,"** %u %s signalled\n",warnings, + (warnings > 1 ? "warnings were" : "warning was")); + if (errors) + fprintf(stderr,"** %u %s found\n",errors, + (errors > 1 ? "errors were" : "error was")); + else + if (!cmderr) + fprintf(stderr,"No errors were found\n"); + } + freeblocks(); + } else + cmderr = TRUE; + dumpalloc("termination"); + if (cmderr || errors) + exit(1); + return (0); +} + +#endif diff --git a/src/secaudit.h b/src/secaudit.h new file mode 100755 index 0000000..7f0d6da --- a/dev/null +++ b/src/secaudit.h @@ -0,0 +1,731 @@ +/* + * General declarations for secaudit + * + * These declarations are organized to enable code sharing with ntfs-3g + * library, but should only be used to build tools runnable both + * on Linux (dynamic linking) and Windows (static linking) + * + * Copyright (c) 2007-2009 Jean-Pierre Andre + * + */ + +/* + * 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 (in the main directory of the NTFS-3G + * distribution in the file COPYING); if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * General parameters which may have to be adapted to needs + */ + +#define SELFTESTS 1 /* include code for self-testing */ +#define POSIXACLS 0 /* include code for processing Posix ACLs */ +#define NOREVBOM 0 /* temporary */ + +#define OWNERFROMACL 1 /* must match option in security.c */ + +#define MAXATTRSZ 65536 /* Max sec attr size (16448 met for WinXP) */ +#define MAXSECURID 262144 +#define SECBLKSZ 8 +#define MAXFILENAME 4096 +#define FORCEMASK 0 /* Special (dangerous) option -m to force a mask */ +#define MAXLINE 80 /* maximum processed size of a line */ +#define BUFSZ 1024 /* buffer size to read mapping file */ +#define LINESZ 120 /* maximum useful size of a mapping line */ + +/* + * Definitions for Linux + * Use explicit or implicit dynamic linking + */ + +#ifdef HAVE_CONFIG_H +#undef POSIXACLS /* override default by configure option */ +#define USESTUBS 1 /* API stubs generated at link time */ +#else +#define USESTUBS 0 /* direct calls to API, based on following definitions */ +#define ENVNTFS3G "NTFS3G" +#define LIBFILE64 "/lib64/libntfs-3g.so.4921" +#define LIBFILE "/lib/libntfs-3g.so.4921" +#endif + +#define MAPDIR ".NTFS-3G" +#define MAPFILE "UserMapping" +#define MAGIC_API 0x09042009 + +#ifndef _NTFS_ENDIANS_H + +typedef char s8; +typedef short s16; +typedef long long s64; +typedef unsigned char u8; +typedef unsigned short le16, be16, u16; +typedef unsigned long long u64; +#ifdef STSC +typedef long s32; +typedef unsigned long le32, be32, u32; +#else +typedef int s32; +typedef unsigned int le32, be32, u32; +#endif + +#ifdef STSC +#define endian_rev16(x) ((((x) & 255L) << 8) + (((x) >> 8) & 255L)) +#define endian_rev32(x) ((((x) & 255L) << 24) + (((x) & 0xff00L) << 8) \ + + (((x) >> 8) & 0xff00L) + (((x) >> 24) & 255L)) +#else +#define endian_rev16(x) ((((x) & 255) << 8) + (((x) >> 8) & 255)) +#define endian_rev32(x) ((((x) & 255) << 24) + (((x) & 0xff00) << 8) \ + + (((x) >> 8) & 0xff00) + (((x) >> 24) & 255)) +#endif +#define endian_rev64(x) ((((x) & 255LL) << 56) + (((x) & 0xff00LL) << 40) \ + + (((x) & 0xff0000LL) << 24) + (((x) & 0xff000000LL) << 8) \ + + (((x) >> 8) & 0xff000000LL) + (((x) >> 24) & 0xff0000LL) \ + + (((x) >> 40) & 0xff00LL) + (((x) >> 56) & 255LL)) + +#if __BYTE_ORDER == __LITTLE_ENDIAN + +#define cpu_to_be16(x) endian_rev16(x) +#define cpu_to_be32(x) endian_rev32(x) +#define cpu_to_le16(x) (x) +#define cpu_to_le32(x) (x) +#define cpu_to_le64(x) (x) +#define le16_to_cpu(x) (x) +#define le32_to_cpu(x) (x) +#define le64_to_cpu(x) (x) + +#else + +#define cpu_to_be16(x) (x) +#define cpu_to_be32(x) (x) +#define cpu_to_le16(x) endian_rev16(x) +#define cpu_to_le32(x) endian_rev32(x) +#define cpu_to_le64(x) endian_rev64(x) +#define le16_to_cpu(x) endian_rev16(x) +#define le32_to_cpu(x) endian_rev32(x) +#define le64_to_cpu(x) endian_rev64(x) + +#endif + +#define const_le16_to_cpu(x) le16_to_cpu(x) +#define const_cpu_to_le16(x) cpu_to_le16(x) +#define const_cpu_to_le32(x) cpu_to_le32(x) +#define const_cpu_to_be16(x) cpu_to_be16(x) +#define const_cpu_to_be32(x) cpu_to_be32(x) + +#endif /* _NTFS_ENDIANS_H */ + +#ifndef FALSE +enum { FALSE, TRUE } ; +#endif /* FALSE */ + +#ifdef WIN32 + +typedef unsigned short uid_t; +typedef unsigned short gid_t; + +#define UNICODE(c) ((unsigned short)(c)) + +#define __attribute__(x) + +#else + +#ifndef BOOL +typedef int BOOL; /* Already defined in windows.h */ +#endif /* BOOL */ + +#ifdef STSC + +#define ENOTSUP 95 + +#endif /* STSC */ + +typedef u32 DWORD; /* must be 32 bits whatever the platform */ +typedef DWORD *LPDWORD; + +#define MS_NONE 0 /* no flag for mounting the device */ +#define MS_RDONLY 1 /* flag for mounting the device read-only */ + +#endif /* WIN32 */ + +#if defined(WIN32) | defined(STSC) + +/* + * On non-Linux computers, there is no mount and the user mapping + * if fetched from a real file (or a dummy one for self tests) + */ + +#define NTFS_FIND_USID(map,uid,buf) ntfs_find_usid(map,uid,buf) +#define NTFS_FIND_GSID(map,gid,buf) ntfs_find_gsid(map,gid,buf) +#define NTFS_FIND_USER(map,usid) ntfs_find_user(map,usid) +#define NTFS_FIND_GROUP(map,gsid) ntfs_find_group(map,gsid) + +#else + +/* + * On Linux computers, there is a mount and the user mapping + * if either obtained through the mount process or fetched + * from a dummy file for self-tests + */ + +#define NTFS_FIND_USID(map,uid,buf) (mappingtype != MAPEXTERN ? \ + ntfs_find_usid(map,uid,buf) : relay_find_usid(map,uid,buf)) +#define NTFS_FIND_GSID(map,gid,buf) (mappingtype != MAPEXTERN ? \ + ntfs_find_gsid(map,gid,buf) : relay_find_gsid(map,gid,buf)) +#define NTFS_FIND_USER(map,usid) (mappingtype != MAPEXTERN ? \ + ntfs_find_user(map,usid) : relay_find_user(map,usid)) +#define NTFS_FIND_GROUP(map,gsid) (mappingtype != MAPEXTERN ? \ + ntfs_find_group(map,gsid) : relay_find_group(map,gsid)) + +#endif + +/* + * A few name hijackings or definitions + * needed for using code from ntfs-3g + */ + +#ifdef WIN32 +#define ACL MY_ACL +#define SID MY_SID +#define ACCESS_ALLOWED_ACE MY_ACCESS_ALLOWED_ACE +#define ACCESS_DENIED_ACE MY_ACCESS_DENIED_ACE +#define FILE_ATTRIBUTE_REPARSE_POINT 0x400 +#define IO_REPARSE_TAG_MOUNT_POINT 0xa0000003 +#define IO_REPARSE_TAG_SYMLINK 0xa000000c +#else +#define SE_OWNER_DEFAULTED const_cpu_to_le16(1) +#define SE_GROUP_DEFAULTED const_cpu_to_le16(2) +#define SE_DACL_PRESENT const_cpu_to_le16(4) +#define SE_SACL_PRESENT const_cpu_to_le16(0x10) +#define SE_DACL_DEFAULTED const_cpu_to_le16(8) +#define SE_SELF_RELATIVE const_cpu_to_le16(0x8000) +#define SID_REVISION 1 +#endif /* WIN32 */ +#define SE_DACL_PROTECTED const_cpu_to_le16(0x1000) +#define SE_SACL_PROTECTED const_cpu_to_le16(0x2000) +#define SE_DACL_AUTO_INHERITED const_cpu_to_le16(0x400) +#define SE_SACL_AUTO_INHERITED const_cpu_to_le16(0x800) +#define SE_DACL_AUTO_INHERIT_REQ cpu_to_le16(0x100) +#define SE_SACL_AUTO_INHERIT_REQ cpu_to_le16(0x200) + +typedef le16 ntfschar; + +typedef struct { + le32 a; + le16 b,c; + struct { + le16 m,n,o,p, q,r,s,t; + } ; +} GUID; + +#define ntfs_log_error(args...) do { printf("** " args); if (!isatty(1)) fprintf(stderr,args); } while(0) + +/* + * Struct to hold the input mapping file + * (private to this module) + */ + +struct MAPLIST { + struct MAPLIST *next; + char *uidstr; /* uid text from the same record */ + char *gidstr; /* gid text from the same record */ + char *sidstr; /* sid text from the same record */ + char maptext[LINESZ + 1]; +}; + +/* + * A few dummy declarations needed for using code from security.c + */ + +#define MFT_RECORD_IS_DIRECTORY const_cpu_to_le16(1) + +struct SECURITY_DATA { + u64 offset; + char *attr; + u32 hash; + u32 length; + unsigned int filecount:16; + unsigned int mode:12; + unsigned int flags:4; +} ; + +#define AUTH1 3141592653U +#define AUTH2 589793238 +#define AUTH3 462843383 +#define OWNERID 1016 +#define GROUPID 513 + + +#define INSDS1 1 +#define INSDS2 2 +#define INSII 4 +#define INSDH 8 + +#ifdef WIN32 + +typedef enum { RECSHOW, RECSET, RECSETPOSIX } RECURSE; + +#endif + +/* + * A type large enough to hold any SID + */ + +typedef char BIGSID[40]; + +/* + * Declarations for memory allocation checks + */ + +struct CHKALLOC + { + struct CHKALLOC *next; + void *alloc; + const char *file; + int line; + size_t size; + } ; + +#if defined(WIN32) | defined(STSC) + +#define S_ISVTX 01000 +#define S_ISGID 02000 +#define S_ISUID 04000 +#define S_IXUSR 0100 +#define S_IWUSR 0200 +#define S_IRUSR 0400 +#define S_IXGRP 010 +#define S_IWGRP 020 +#define S_IRGRP 040 +#define S_IXOTH 001 +#define S_IWOTH 002 +#define S_IROTH 004 + +#endif + +#ifdef WIN32 +#else +/* + * + * See http://msdn2.microsoft.com/en-us/library/aa379649.aspx + */ + +typedef enum { + DACL_SECURITY_INFORMATION = 4, // The DACL of the object is being referenced. + SACL_SECURITY_INFORMATION = 8, // The SACL of the object is being referenced. + LABEL_SECURITY_INFORMATION = 8, // The mandatory integrity label is being referenced. + GROUP_SECURITY_INFORMATION = 2, // The primary group identifier of the object is being referenced. + OWNER_SECURITY_INFORMATION = 1, // The owner identifier of the object is being referenced. +} SECURITY_INFORMATION; + +#define STANDARD_RIGHTS_READ cpu_to_le32(0x20000) +#define STANDARD_RIGHTS_WRITE cpu_to_le32(0x20000) +#define STANDARD_RIGHTS_EXECUTE cpu_to_le32(0x20000) +#define STANDARD_RIGHTS_REQUIRED cpu_to_le32(0xf0000) + +#endif + +typedef struct SECHEAD { + s8 revision; + s8 alignment; + le16 control; + le32 owner; + le32 group; + le32 sacl; + le32 dacl; +} SECURITY_DESCRIPTOR_RELATIVE; + +typedef struct ACL { + s8 revision; + s8 alignment1; + le16 size; + le16 ace_count; + le16 alignment2; +} ACL; + +typedef struct { + union { + struct { + unsigned char revision; + unsigned char sub_authority_count; + } ; + struct { + /* evade an alignment problem when a 4 byte field */ + /* in a struct implies alignment of the struct */ + le16 dummy; + be16 high_part; + be32 low_part; + } identifier_authority; + } ; + le32 sub_authority[1]; +} SID; + +typedef u8 ACE_FLAGS; + +typedef struct ACE { + u8 type; + u8 flags; + le16 size; + le32 mask; + SID sid; +} ACCESS_ALLOWED_ACE, ACCESS_DENIED_ACE; + + +/* + * item in the mapping list + */ + +struct MAPPING { + struct MAPPING *next; + int xid; /* linux id : uid or gid */ + SID *sid; /* Windows id : usid or gsid */ + int grcnt; /* group count (for users only) */ + gid_t *groups; /* groups which the user is member of */ +}; + +/* + * Posix ACL structures + */ + +struct POSIX_ACE { + u16 tag; + u16 perms; + s32 id; +} ; + +struct POSIX_ACL { + u8 version; + u8 flags; + u16 filler; + struct POSIX_ACE ace[0]; +} ; + +struct POSIX_SECURITY { + mode_t mode; + int acccnt; + int defcnt; + int firstdef; + u16 tagsset; + struct POSIX_ACL acl; +} ; + +/* + * Posix tags, cpu-endian 16 bits + */ + +enum { + POSIX_ACL_USER_OBJ = 1, + POSIX_ACL_USER = 2, + POSIX_ACL_GROUP_OBJ = 4, + POSIX_ACL_GROUP = 8, + POSIX_ACL_MASK = 16, + POSIX_ACL_OTHER = 32, + POSIX_ACL_SPECIAL = 64 /* internal use only */ +} ; + +/* + * Posix permissions, cpu-endian 16 bits + */ + +enum { + POSIX_PERM_X = 1, + POSIX_PERM_W = 2, + POSIX_PERM_R = 4, + POSIX_PERM_DENIAL = 64 /* internal use only */ +} ; + +#define POSIX_VERSION 2 + +/* + * A few definitions adapted from winnt.h + * (Windows version uses actual definitions from winnt.h, which are + * not compatible with code from security.c on a big-endian computer) + */ + +#ifndef WIN32 + +#define DELETE cpu_to_le32(0x00010000L) +#define READ_CONTROL cpu_to_le32(0x00020000L) +#define WRITE_DAC cpu_to_le32(0x00040000L) +#define WRITE_OWNER cpu_to_le32(0x00080000L) +#define SYNCHRONIZE cpu_to_le32(0x00100000L) + + +#define FILE_READ_DATA cpu_to_le32( 0x0001 ) // file & pipe +#define FILE_LIST_DIRECTORY cpu_to_le32( 0x0001 ) // directory + +#define FILE_WRITE_DATA cpu_to_le32( 0x0002 ) // file & pipe +#define FILE_ADD_FILE cpu_to_le32( 0x0002 ) // directory + +#define FILE_APPEND_DATA cpu_to_le32( 0x0004 ) // file +#define FILE_ADD_SUBDIRECTORY cpu_to_le32( 0x0004 ) // directory +#define FILE_CREATE_PIPE_INSTANCE cpu_to_le32( 0x0004 ) // named pipe + + +#define FILE_READ_EA cpu_to_le32( 0x0008 ) // file & directory + +#define FILE_WRITE_EA cpu_to_le32( 0x0010 ) // file & directory + +#define FILE_EXECUTE cpu_to_le32( 0x0020 ) // file +#define FILE_TRAVERSE cpu_to_le32( 0x0020 ) // directory + +#define FILE_DELETE_CHILD cpu_to_le32( 0x0040 ) // directory + +#define FILE_READ_ATTRIBUTES cpu_to_le32( 0x0080 ) // all + +#define FILE_WRITE_ATTRIBUTES cpu_to_le32( 0x0100 ) // all + +#define FILE_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | \ + cpu_to_le32(0x1FF)) + +#define FILE_GENERIC_READ (STANDARD_RIGHTS_READ |\ + FILE_READ_DATA |\ + FILE_READ_ATTRIBUTES |\ + FILE_READ_EA |\ + SYNCHRONIZE) + + +#define FILE_GENERIC_WRITE (STANDARD_RIGHTS_WRITE |\ + FILE_WRITE_DATA |\ + FILE_WRITE_ATTRIBUTES |\ + FILE_WRITE_EA |\ + FILE_APPEND_DATA |\ + SYNCHRONIZE) + + +#define FILE_GENERIC_EXECUTE (STANDARD_RIGHTS_EXECUTE |\ + FILE_READ_ATTRIBUTES |\ + FILE_EXECUTE |\ + SYNCHRONIZE) + +#define GENERIC_READ cpu_to_le32(0x80000000L) +#define GENERIC_WRITE cpu_to_le32(0x40000000L) +#define GENERIC_EXECUTE cpu_to_le32(0x20000000L) +#define GENERIC_ALL cpu_to_le32(0x10000000L) + + +#define OBJECT_INHERIT_ACE (0x1) +#define CONTAINER_INHERIT_ACE (0x2) +#define NO_PROPAGATE_INHERIT_ACE (0x4) +#define INHERIT_ONLY_ACE (0x8) +#define VALID_INHERIT_FLAGS (0xF) + +/* + * Other useful definitions + */ + +#define ACL_REVISION 2 +#define ACCESS_ALLOWED_ACE_TYPE 0 +#define ACCESS_DENIED_ACE_TYPE 1 +#define SECURITY_DESCRIPTOR_REVISION 1 + +#endif /* !WIN32 */ + +#ifndef ACL_REVISION_DS /* not always defined in */ +#define ACL_REVISION_DS 4 +#endif + +/* + * Matching of ntfs permissions to Linux permissions + * these constants are adapted to endianness + * when setting, set them all + * when checking, check one is present + */ + + /* flags which are set to mean exec, write or read */ + +#define FILE_READ (FILE_READ_DATA) +#define FILE_WRITE (FILE_WRITE_DATA | FILE_APPEND_DATA \ + | READ_CONTROL | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA) +#define FILE_EXEC (FILE_EXECUTE) +#define DIR_READ FILE_LIST_DIRECTORY +#define DIR_WRITE (FILE_ADD_FILE | FILE_ADD_SUBDIRECTORY | FILE_DELETE_CHILD \ + | READ_CONTROL | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA) +#define DIR_EXEC (FILE_TRAVERSE) + + /* flags tested for meaning exec, write or read */ + /* tests for write allow for interpretation of a sticky bit */ + +#define FILE_GREAD (FILE_READ_DATA | GENERIC_READ) +#define FILE_GWRITE (FILE_WRITE_DATA | FILE_APPEND_DATA | GENERIC_WRITE) +#define FILE_GEXEC (FILE_EXECUTE | GENERIC_EXECUTE) +#define DIR_GREAD (FILE_LIST_DIRECTORY | GENERIC_READ) +#define DIR_GWRITE (FILE_ADD_FILE | FILE_ADD_SUBDIRECTORY | GENERIC_WRITE) +#define DIR_GEXEC (FILE_TRAVERSE | GENERIC_EXECUTE) + + /* standard owner (and administrator) rights */ + +#define OWNER_RIGHTS (DELETE | READ_CONTROL | WRITE_DAC | WRITE_OWNER \ + | SYNCHRONIZE \ + | FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES \ + | FILE_READ_EA | FILE_WRITE_EA) + + /* standard world rights */ + +#define WORLD_RIGHTS (READ_CONTROL | FILE_READ_ATTRIBUTES | FILE_READ_EA \ + | SYNCHRONIZE) + + /* inheritance flags for files and directories */ + +#define FILE_INHERITANCE NO_PROPAGATE_INHERIT_ACE +#define DIR_INHERITANCE (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE) + +/* + * To identify NTFS ACL meaning Posix ACL granted to root + * we use rights always granted to anybody, so they have no impact + * either on Windows or on Linux. + */ + +#define ROOT_OWNER_UNMARK SYNCHRONIZE /* ACL granted to root as owner */ +#define ROOT_GROUP_UNMARK FILE_READ_EA /* ACL granted to root as group */ + + +struct SII { /* this is an image of an $SII index entry */ + le16 offs; + le16 size; + le32 fill1; + le16 indexsz; + le16 indexksz; + le16 flags; + le16 fill2; + le32 keysecurid; + + /* did not find official description for the following */ + le32 hash; + le32 securid; + le32 dataoffsl; /* documented as badly aligned */ + le32 dataoffsh; + le32 datasize; +} ; + +struct SDH { /* this is an image of an $SDH index entry */ + le16 offs; + le16 size; + le32 fill1; + le16 indexsz; + le16 indexksz; + le16 flags; + le16 fill2; + le32 keyhash; + le32 keysecurid; + + /* did not find official description for the following */ + le32 hash; + le32 securid; + le32 dataoffsl; + le32 dataoffsh; + le32 datasize; + le32 fill3; + } ; + +#ifndef INVALID_FILE_ATTRIBUTES /* not defined in old windows.h */ +#define INVALID_FILE_ATTRIBUTES (-1) +#endif + +enum { MAPUSERS, MAPGROUPS, MAPCOUNT } ; + +struct SECURITY_CONTEXT { + struct MAPPING *mapping[MAPCOUNT]; +} ; + +typedef enum { MAPNONE, MAPEXTERN, MAPLOCAL, MAPDUMMY } MAPTYPE; + + + +struct passwd { + uid_t pw_uid; +} ; + +struct group { + gid_t gr_gid; +} ; + +typedef int (*FILEREADER)(void *fileid, char *buf, size_t size, off_t pos); + +/* + * Data defined in secaudit.c + */ + +extern MAPTYPE mappingtype; + +/* + * Functions defined in acls.c + */ + +BOOL ntfs_valid_descr(const char *securattr, unsigned int attrsz); +BOOL ntfs_valid_posix(const struct POSIX_SECURITY *pxdesc); +BOOL ntfs_valid_pattern(const SID *sid); +BOOL ntfs_same_sid(const SID *first, const SID *second); + + +int ntfs_sid_size(const SID * sid); +unsigned int ntfs_attr_size(const char *attr); + +const SID *ntfs_find_usid(const struct MAPPING *usermapping, + uid_t uid, SID *pdefsid); +const SID *ntfs_find_gsid(const struct MAPPING *groupmapping, + gid_t gid, SID *pdefsid); +uid_t ntfs_find_user(const struct MAPPING *usermapping, const SID *usid); +gid_t ntfs_find_group(const struct MAPPING *groupmapping, const SID * gsid); +const SID *ntfs_acl_owner(const char *secattr); + +void ntfs_sort_posix(struct POSIX_SECURITY *pxdesc); +int ntfs_merge_mode_posix(struct POSIX_SECURITY *pxdesc, mode_t mode); + + +struct POSIX_SECURITY *ntfs_build_permissions_posix( + struct MAPPING* const mapping[], + const char *securattr, + const SID *usid, const SID *gsid, BOOL isdir); +int ntfs_build_permissions(const char *securattr, + const SID *usid, const SID *gsid, BOOL isdir); +struct MAPLIST *ntfs_read_mapping(FILEREADER reader, void *fileid); +struct MAPPING *ntfs_do_user_mapping(struct MAPLIST *firstitem); +struct MAPPING *ntfs_do_group_mapping(struct MAPLIST *firstitem); +void ntfs_free_mapping(struct MAPPING *mapping[]); + +struct POSIX_SECURITY *ntfs_merge_descr_posix(const struct POSIX_SECURITY *first, + const struct POSIX_SECURITY *second); +char *ntfs_build_descr_posix(struct MAPPING* const mapping[], + struct POSIX_SECURITY *pxdesc, + int isdir, const SID *usid, const SID *gsid); +char *ntfs_build_descr(mode_t mode, + int isdir, const SID * usid, const SID * gsid); + +/* + * Functions defined in secaudit.c + */ + +void *chkmalloc(size_t, const char*, int); +void *chkcalloc(size_t, size_t, const char *, int); +void chkfree(void*, const char*, int); +BOOL chkisalloc(void*, const char*, int); +void dumpalloc(const char*); + +#define malloc(sz) chkmalloc(sz, __FILE__, __LINE__) +#define calloc(cnt,sz) chkcalloc(cnt, sz, __FILE__, __LINE__) +#define free(ptr) chkfree(ptr, __FILE__, __LINE__) +#define isalloc(ptr) chkisalloc(ptr, __FILE__, __LINE__) +#define ntfs_malloc(sz) chkmalloc(sz, __FILE__, __LINE__) + +struct passwd *getpwnam(const char *user); +struct group *getgrnam(const char *group); + +const SID *relay_find_usid(const struct MAPPING *usermapping, + uid_t uid, SID *pdefsid); +const SID *relay_find_gsid(const struct MAPPING *groupmapping, + gid_t gid, SID *pdefsid); +uid_t relay_find_user(const struct MAPPING *usermapping, const SID *usid); +gid_t relay_find_group(const struct MAPPING *groupmapping, const SID * gsid); + diff --git a/src/test.c b/src/test.c new file mode 100755 index 0000000..caf6aec --- a/dev/null +++ b/src/test.c @@ -0,0 +1,88 @@ +#include +#include + +//#include +#include +#include +#include + +//#define O_RDWR 00000000 +//#define __u64 unsigned long long + + +#define BUFFERSIZE 16 + + +/***************************************** +* +* /bin/test /media/usba1/ +* +*****************************************/ + +int main(int argc,char* argv[]) +{ + char *filestr = argv[1]; + int fd ; + __s64 start= 0; + __s32 total=0; + __u32 start_h= 0;//, total_h=0; + __u32 start_l= 0;//, total_l=0; + __u8 buffer[BUFFERSIZE]; + + if(argc < 4) + { + printf("< 4 args\n"); + printf("format:filestr start_h(0x):start_l size(0x)\n"); + return -1; + } + + fd =open(filestr,O_RDWR|O_LARGEFILE,0); + if(fd < 0) + { + printf("open %s fail\n",filestr); + return -1; + } + + sscanf(argv[2],"0x%x:%x",&start_h,&start_l); + sscanf(argv[3],"0x%x",&total); + + start=((__s64)start_h<<32)+start_l; + if(start < 0 || total< 0 ) + { + printf("start or total <0 \n"); + return -1; + } + + if(start!=lseek64(fd,start,SEEK_SET)) + { + printf("lseek64 fail \n"); + return -1; + } + + printf("read start from 0x%x:%x\n",start_h ,start_l ); + printf("total= 0x%x bytes\n",total ); + + for ( ;total>0 ; total-=BUFFERSIZE) + { + int i; + memset(buffer,0,BUFFERSIZE); + if(read(fd,buffer,BUFFERSIZE)<0) + { + printf("read at 0x%x%x fail\n", (__u32)(start>>32),(__u32)(start&0xffffffff)); + printf("errno=%d\n",errno); + break; + } + + for(i=0;i +#include +#include +#include +#ifdef HAVE_SYS_TYPES_H +#include +#endif + +#include +#include + +/* + * Define the security API according to platform + */ + +#ifdef WIN32 + +#include +#include + +#define STATIC + +typedef enum { DENIED, AGREED } boolean; + +#else + +#include +#include + +typedef enum { DENIED, AGREED } boolean, BOOL; +typedef unsigned int DWORD; /* must be 32 bits whatever the platform */ +typedef DWORD *LPDWORD; + +enum { OWNER_SECURITY_INFORMATION = 1, + GROUP_SECURITY_INFORMATION = 2, + DACL_SECURITY_INFORMATION = 4, + SACL_SECURITY_INFORMATION = 8 +} ; + +struct CALLBACK { + const char *accname; + const char *dir; + int levels; + int docset; +} ; + +typedef int (*dircallback)(struct CALLBACK *context, char *ntfsname, + int length, int type, long long pos, unsigned long long mft_ref, + unsigned int dt_type); + +#if USESTUBS + +#define STATIC static + +BOOL ntfs_get_file_security(void *scapi, + const char *path, DWORD selection, + char *buf, DWORD buflen, LPDWORD psize); +BOOL ntfs_set_file_security(void *scapi, + const char *path, DWORD selection, const char *attr); +BOOL ntfs_read_directory(void *scapi, + const char *path, dircallback callback, void *context); +void *ntfs_initialize_file_security(const char *device, + int flags); +BOOL ntfs_leave_file_security(void *scapi); + +#else + +#define STATIC + +BOOL (*ntfs_get_file_security)(void *scapi, + const char *path, DWORD selection, + char *buf, DWORD buflen, LPDWORD psize); +BOOL (*ntfs_set_file_security)(void *scapi, + const char *path, DWORD selection, const char *attr); +BOOL (*ntfs_read_directory)(void *scapi, + const char *path, dircallback callback, void *context); +void *(*ntfs_initialize_file_security)(const char *device, + int flags); +BOOL (*ntfs_leave_file_security)(void *scapi); + +#endif + +STATIC boolean open_security_api(void); +STATIC boolean close_security_api(void); +STATIC boolean open_volume(const char *volume); +STATIC boolean close_volume(const char *volume); + +#endif + +struct MAPPING { + struct MAPPING *next; + const char *uidstr; + const char *gidstr; + const char *sidstr; + const unsigned char *sid; + const char *login; + boolean defined; +}; + +struct MAPPING *firstmapping; +struct MAPPING *lastmapping; + +#ifdef WIN32 +char *currentwinname; +char *currentdomain; +unsigned char *currentsid; +#endif + +#ifndef WIN32 + +void *ntfs_handle; +void *ntfs_context = (void*)NULL; + +/* + * Shut down compiler warnings for unused parameters + */ + +static long unused(const void *p) +{ +return ((long)p); +} + +/* + * Open and close the security API (platform dependent) + */ + +STATIC boolean open_security_api(void) +{ +#if USESTUBS + return (AGREED); +#else + char *error; + boolean err; + const char *libfile; + + err = AGREED; + libfile = getenv(ENVNTFS3G); + if (!libfile) + libfile = (sizeof(char*) == 8 ? LIBFILE64 : LIBFILE); + ntfs_handle = dlopen(libfile,RTLD_LAZY); + if (ntfs_handle) { + ntfs_initialize_file_security = + dlsym(ntfs_handle,INIT_FILE_SECURITY); + error = dlerror(); + if (error) + fprintf(stderr," %s\n",error); + else { + ntfs_leave_file_security = + dlsym(ntfs_handle,LEAVE_FILE_SECURITY); + ntfs_get_file_security = + dlsym(ntfs_handle,GET_FILE_SECURITY); + ntfs_set_file_security = + dlsym(ntfs_handle,SET_FILE_SECURITY); + ntfs_read_directory = + dlsym(ntfs_handle,READ_DIRECTORY); + err = !ntfs_initialize_file_security + || !ntfs_leave_file_security + || !ntfs_get_file_security + || !ntfs_set_file_security + || !ntfs_read_directory; + if (error) + fprintf(stderr,"ntfs-3g API not available\n"); + } + } else { + fprintf(stderr,"Could not open ntfs-3g library\n"); + fprintf(stderr,"\nPlease set environment variable \"" ENVNTFS3G "\"\n"); + fprintf(stderr,"to appropriate path and retry\n"); + } + return (!err); +#endif +} + +STATIC boolean close_security_api(void) +{ +#if USESTUBS + return (0); +#else + return (!dlclose(ntfs_handle)); +#endif +} + +/* + * Open and close a volume (platform dependent) + * assuming a single volume needs to be opened at any time + */ + +STATIC boolean open_volume(const char *volume) +{ + boolean ok; + + ok = DENIED; + if (!ntfs_context) { + ntfs_context = ntfs_initialize_file_security(volume,0); + if (ntfs_context) { + fprintf(stderr,"\"%s\" opened\n",volume); + ok = AGREED; + } else { + fprintf(stderr,"Could not open \"%s\"\n",volume); + fprintf(stderr,"Make sure \"%s\" is not mounted\n",volume); + } + } else + fprintf(stderr,"A volume is already open\n"); + return (ok); +} + +STATIC boolean close_volume(const char *volume) +{ + boolean r; + + r = ntfs_leave_file_security(ntfs_context); + if (r) + fprintf(stderr,"\"%s\" closed\n",volume); + else + fprintf(stderr,"Could not close \"%s\"\n",volume); + ntfs_context = (void*)NULL; + return (r); +} + +/* + * A poor man's conversion of Unicode to UTF8 + * We are assuming outputs to terminal expect UTF8 + */ + +STATIC void to_utf8(char *dst, const char *src, unsigned int cnt) +{ + unsigned int ch; + unsigned int i; + + for (i=0; i> 6); + *dst++ = 0x80 + (ch & 63); + } else { + *dst++ = 0xe0 + (ch >> 12); + *dst++ = 0x80 + ((ch >> 6) & 63); + *dst++ = 0x80 + (ch & 63); + } + } + *dst = 0; +} + +STATIC int utf8_size(const char *src, unsigned int cnt) +{ + unsigned int ch; + unsigned int i; + int size; + + size = 0; + for (i=0; isidstr, sidstr)) + mapping = mapping->next; + if (mapping + && (mapping->defined + || !accname + || !strcmp(mapping->login, accname))) + free(sidstr); /* decision already known */ + else { + do { + reject = DENIED; + printf("\n"); + if (accname) + printf("Under Windows login \"%s\"\n", accname); + printf(" file \"%s\" has no mapped %s\n", + filename,(type ? "group" : "owner")); + printf("By which Linux login should this file be owned ?\n"); + printf("Enter %s of login, or just press \"enter\" if this file\n", + (type ? "gid" : "uid")); + printf("does not belong to a user, or you do not known to whom\n"); + printf("\n"); + if (type) + printf("Group : "); + else + printf("User : "); + p = fgets(buf, 80, stdin); + if (p && p[0] && (p[strlen(p) - 1] == '\n')) + p[strlen(p) - 1] = '\0'; + + if (p && p[0] + && ((p[0] == '0') || !strcmp(p, "root"))) { + printf("Please do not map users to root\n"); + printf("Administrators will be mapped automatically\n"); + reject = AGREED; + } + if (reject) + printf("Please retry\n"); + } while (reject); + if (!mapping) { + mapping = + (struct MAPPING *) + malloc(sizeof(struct MAPPING)); + mapping->next = (struct MAPPING *)NULL; + mapping->defined = DENIED; + if (lastmapping) + lastmapping->next = mapping; + else + firstmapping = mapping; + lastmapping = mapping; + } + if (mapping) { + if (p && p[0]) { + idstr = (char *)malloc(strlen(p) + 1); + if (idstr) { + strcpy(idstr, p); + if (type) { + mapping->uidstr = ""; + mapping->gidstr = idstr; + } else { + mapping->uidstr = idstr; + mapping->gidstr = idstr; + } + mapping->defined = AGREED; + } + } + mapping->sidstr = sidstr; + if (accname) { + login = (char*)malloc(strlen(accname) + 1); + if (login) + strcpy(login,accname); + mapping->login = login; + } else + mapping->login = (char*)NULL; + sidsz = 8 + sid[1]*4; + p = (char*)malloc(sidsz); + if (p) { + memcpy(p, sid, sidsz); + } + mapping->sid = (unsigned char*)p; + } + } + } +} + +STATIC void listaclusers(const char *accname, const unsigned char *attr, int off) +{ + int i; + int cnt; + int x; + + cnt = get2l(attr, off + 4); + x = 8; + for (i = 0; i < cnt; i++) { + domapping(accname, (char *)NULL, &attr[off + x + 8], 2); + x += get2l(attr, off + x + 2); + } +} + +#ifdef WIN32 + +STATIC void account(const char *accname, const char *dir, const char *name, int type) +{ + unsigned char attr[MAXATTRSZ]; + unsigned long attrsz; + char *fullname; + int attrib; + + fullname = (char *)malloc(strlen(dir) + strlen(name) + 2); + if (fullname) { + strcpy(fullname, dir); + strcat(fullname, "\\"); + strcat(fullname, name); + attrib = GetFileAttributes(fullname); + if (attrib & 0x10) { /* only directories processed */ + if (GetFileSecurity + (fullname, OWNER_SECURITY_INFORMATION, attr, MAXATTRSZ, + &attrsz)) { + domapping(accname, name, &attr[20], 0); + attrsz = 0; + if (GetFileSecurity + (fullname, GROUP_SECURITY_INFORMATION, attr, + MAXATTRSZ, &attrsz)) + domapping(accname, name, &attr[20], 1); + else + printf(" No group SID\n"); + attrsz = 0; + if (GetFileSecurityA + (fullname, DACL_SECURITY_INFORMATION, attr, + MAXATTRSZ, &attrsz)) { + if (type == 0) + listaclusers(accname, attr, 20); + } else + printf + (" No discretionary access control list\n"); + } + } + free(fullname); + } +} + +#else + +STATIC void account(const char *accname, const char *dir, const char *name, int type) +{ + unsigned char attr[MAXATTRSZ]; + DWORD attrsz; + char *fullname; + + fullname = (char *)malloc(strlen(dir) + strlen(name) + 2); + if (fullname) { + strcpy(fullname, dir); + strcat(fullname, "/"); + strcat(fullname, name); + if (ntfs_get_file_security(ntfs_context, + fullname, OWNER_SECURITY_INFORMATION, + (char*)attr, MAXATTRSZ, &attrsz)) { + domapping(accname, name, &attr[20], 0); + attrsz = 0; + if (ntfs_get_file_security(ntfs_context, + fullname, GROUP_SECURITY_INFORMATION, + (char*)attr, MAXATTRSZ, &attrsz)) + domapping(accname, name, &attr[20], 1); + else + printf(" No group SID\n"); + attrsz = 0; + if (ntfs_get_file_security(ntfs_context, + fullname, DACL_SECURITY_INFORMATION, + (char*)attr, MAXATTRSZ, &attrsz)) { + if (type == 0) + listaclusers(accname, attr, 20); + } else + printf(" No discretionary access control list for %s !\n", + dir); + } + free(fullname); + } +} + +#endif + + +/* + * recursive search of file owners and groups in a directory + */ + +#ifdef WIN32 + +STATIC boolean recurse(const char *accname, const char *dir, int levels) +{ + WIN32_FIND_DATA found; + HANDLE search; + char *filter; + char *fullname; + boolean err; + + err = DENIED; + filter = (char *)malloc(strlen(dir) + 5); + if (filter) { + strcpy(filter, dir); + strcat(filter, "\\*.*"); + search = FindFirstFile(filter, &found); + if (search != INVALID_HANDLE_VALUE) { + do { + if (found.cFileName[0] != '.') { + account(accname, dir, found.cFileName,1); + if (levels > 0) { + fullname = + (char *)malloc(strlen(dir) + + strlen(found.cFileName) + + 2); + if (fullname) { + strcpy(fullname, dir); + strcat(fullname, "\\"); + strcat(fullname, + found.cFileName); + recurse(accname, + fullname, + levels - 1); + free(fullname); + } + } + } + } while (FindNextFile(search, &found)); + FindClose(search); + } + free(filter); + } else { + printf("Directory %s not found\n",dir); + err = AGREED; + } + return (!err); +} + +#else + +STATIC boolean recurse(const char *accname, const char *dir, int levels, int docset); + +STATIC int callback(struct CALLBACK *context, char *ntfsname, + int length, int type, long long pos, unsigned long long mft_ref, + unsigned int dt_type) +{ + char *fullname; + char *accname; + char *name; + + unused((void*)&pos); + unused((void*)&mft_ref); + unused((void*)&dt_type); + fullname = (char *)malloc(strlen(context->dir) + + utf8_size(ntfsname, length) + 2); + if (fullname) { + if (strcmp(context->dir,"/")) { + strcpy(fullname, context->dir); + strcat(fullname, "/"); + } else + strcpy(fullname,"/"); + /* Unicode to ascii conversion by a lazy man */ + name = &fullname[strlen(fullname)]; + to_utf8(name, ntfsname, length); + /* ignore special files and DOS names */ + if ((type != 2) + && strcmp(name,".") + && strcmp(name,"..") + && (name[0] != '$')) { + switch (context->docset) { + case 2 : + /* + * only "Documents and Settings" + * or "Users" + */ + if (!strcmp(name,OWNERS1) + || !strcmp(name,OWNERS2)) { + recurse((char*)NULL, fullname, 2, 1); + } + break; + /* + * within "Documents and Settings" + * or "Users" + */ + case 1 : + accname = (char*)malloc(strlen(name) + 1); + if (accname) { + strcpy(accname, name); + if (context->levels > 0) + recurse(name, fullname, + context->levels - 1, 0); + } + break; + /* + * not related to "Documents and Settings" + * or "Users" + */ + case 0 : + account(context->accname, context->dir, + name, 1); + if (context->levels > 0) + recurse(context->accname, fullname, + context->levels - 1, 0); + break; + } + } + free(fullname); + } +/* check expected return value */ + return (0); +} + +STATIC boolean recurse(const char *accname, const char *dir, int levels, int docset) +{ + struct CALLBACK context; + boolean err; + + err = DENIED; + context.dir = dir; + context.accname = accname; + context.levels = levels; + context.docset = docset; + ntfs_read_directory(ntfs_context,dir,callback,&context); + return (!err); +} +#endif + +/* + * Search directory "Documents and Settings" for user accounts + */ + +#ifdef WIN32 + +STATIC boolean getusers(const char *dir, int levels) +{ + WIN32_FIND_DATA found; + HANDLE search; + char *filter; + char *fullname; + char *accname; + boolean err; + const char *docset; + + /* first get files from "Documents and Settings" */ + err = DENIED; + if (sizeof(OWNERS1) > sizeof(OWNERS2)) + filter = (char *)malloc(strlen(dir) + strlen(OWNERS1) + 6); + else + filter = (char *)malloc(strlen(dir) + strlen(OWNERS2) + 6); + if (filter) { + docset = OWNERS1; + strcpy(filter, dir); + strcat(filter, "\\"); + strcat(filter, docset); + strcat(filter, "\\*.*"); + search = FindFirstFile(filter, &found); + /* if failed, retry with "Users" */ + if (search == INVALID_HANDLE_VALUE) { + docset = OWNERS2; + strcpy(filter, dir); + strcat(filter, "\\"); + strcat(filter, docset); + strcat(filter, "\\*.*"); + search = FindFirstFile(filter, &found); + } + if (search != INVALID_HANDLE_VALUE) { + do { + if (found.cFileName[0] != '.') { + fullname = + (char *)malloc(strlen(dir) + + strlen(docset) + + strlen(found.cFileName) + 3); + accname = (char *) + malloc(strlen(found.cFileName) + 1); + if (fullname && accname) { + strcpy(accname, + found.cFileName); + + strcpy(fullname, dir); + strcat(fullname, "\\"); + strcat(fullname, docset); + strcat(fullname, "\\"); + strcat(fullname, + found.cFileName); + recurse(accname, fullname, 2); + + free(fullname); + } + } + } while (FindNextFile(search, &found)); + FindClose(search); + } else { + printf("No subdirectory found in %s\\%s\n",dir,docset); + } + /* now search in other directories */ + strcpy(filter, dir); + strcat(filter, "\\*.*"); + search = FindFirstFile(filter, &found); + if (search != INVALID_HANDLE_VALUE) { + do { + if ((found.cFileName[0] != '.') + && strcmp(found.cFileName,OWNERS1) + && strcmp(found.cFileName,OWNERS2)) { + fullname = + (char *)malloc(strlen(dir) + + strlen(found.cFileName) + 2); + if (fullname) { + strcpy(fullname, dir); + strcat(fullname, "\\"); + strcat(fullname, + found.cFileName); + recurse((char*)NULL, fullname, 2); + free(fullname); + } + } + } while (FindNextFile(search, &found)); + FindClose(search); + } else { + printf("No directory found in %s\n",dir); + err = AGREED; + } + } + return (!err); +} + +#else + +STATIC boolean getusers(const char *dir, int levels) +{ + boolean err; + struct CALLBACK context; + + printf("* Search for \"" OWNERS1 "\" and \"" OWNERS2 "\"\n"); + err = DENIED; + context.dir = dir; + context.accname = (const char*)NULL; + context.levels = levels; + context.docset = 2; + ntfs_read_directory(ntfs_context,dir,callback,&context); + printf("* Search for other directories %s\n",dir); + context.docset = 0; + ntfs_read_directory(ntfs_context,dir,callback,&context); + + return (!err); +} + +#endif + +#ifdef WIN32 +/* + * Get the current login name (Win32 only) + */ + +STATIC void loginname(boolean silent) +{ + char *winname; + char *domain; + unsigned char *sid; + unsigned long namesz; + unsigned long sidsz; + unsigned long domainsz; + int nametype; + boolean ok; + int r; + + ok = FALSE; + winname = (char*)malloc(MAXNAMESZ); + domain = (char*)malloc(MAXNAMESZ); + sid = (char*)malloc(MAXSIDSZ); + + namesz = MAXNAMESZ; + domainsz = MAXNAMESZ; + sidsz = MAXSIDSZ; + if (winname + && domain + && sid + && GetUserName(winname,&namesz)) { + winname[namesz] = '\0'; + if (!silent) + printf("Your current user name is %s\n",winname); + nametype = 1; + r = LookupAccountName((char*)NULL,winname,sid,&sidsz, + domain,&domainsz,&nametype); + if (r) { + domain[domainsz] = '\0'; + if (!silent) + printf("Your account domain is %s\n",domain); + ok = AGREED; + } + } + if (ok) { + currentwinname = winname; + currentdomain = domain; + currentsid = sid; + } else { + currentwinname = (char*)NULL; + currentdomain = (char*)NULL; + currentsid = (unsigned char*)NULL; + } +} + +/* + * Minimal output on stdout + */ + +boolean minimal(unsigned char *sid) +{ + const unsigned char *groupsid; + boolean ok; + + ok = DENIED; + if (sid) { + groupsid = makegroupsid(sid); + printf("# %s\n",BANNER); + printf("# For Windows account \"%s\" in domain \"%s\"\n", + currentwinname, currentdomain); + printf("# Replace \"user\" and \"group\" hereafter by matching Linux login\n"); + printf("user::%s\n",decodesid(sid)); + printf(":group:%s\n",decodesid(groupsid)); + ok = AGREED; + } + return (ok); +} + +#endif + +STATIC boolean outputmap(const char *volume, const char *dir) +{ + char buf[256]; + int fn; + char *fullname; + char *backup; + struct MAPPING *mapping; + boolean done; + boolean err; + boolean undecided; +#ifdef WIN32 +#else + struct stat st; + int s; +#endif + + done = DENIED; + fullname = (char *)malloc(strlen(MAPFILE) + 1 + + strlen(volume) + 1 + + (dir ? strlen(dir) + 1 : 0)); + if (fullname) { +#ifdef WIN32 + strcpy(fullname, volume); + if (dir && dir[0]) { + strcat(fullname, "\\"); + strcat(fullname,dir); + } + + /* build directory, if not present */ + if (GetFileAttributes(fullname) & 0x80000000) { + printf("* Creating directory %s\n", fullname); + mkdir(fullname); + } + + strcat(fullname, "\\"); + strcat(fullname, MAPFILE); + printf("\n"); + + if (!(GetFileAttributes(fullname) & 0x80000000)) { + backup = (char*)malloc(strlen(fullname) + 5); + strcpy(backup,fullname); + strcat(backup,".bak"); + unlink(backup); + if (!rename(fullname,backup)) + printf("* Old mapping file moved to %s\n",backup); + } +#else + strcpy(fullname, MAPFILE); + printf("\n"); + + s = stat(fullname,&st); + if (!s) { + backup = (char*)malloc(strlen(fullname + 5)); + strcpy(backup,fullname); + strcat(backup,".bak"); + if (rename(fullname,backup)) + printf("* Old mapping file moved to %s\n",backup); + } +#endif + + printf("* Creating file %s\n", fullname); + err = DENIED; +#ifdef WIN32 + fn = open(fullname,O_CREAT + O_TRUNC + O_WRONLY + O_BINARY, + S_IREAD + S_IWRITE); +#else + fn = open(fullname,O_CREAT + O_TRUNC + O_WRONLY, + S_IREAD + S_IWRITE); +#endif + if (fn > 0) { + sprintf(buf,"# %s\n",BANNER); + if (!write(fn,buf,strlen(buf))) + err = AGREED; + printf("%s",buf); + undecided = DENIED; + /* records for owner only or group only */ + for (mapping = firstmapping; mapping && !err; + mapping = mapping->next) + if (mapping->defined + && (!mapping->uidstr[0] || !mapping->gidstr[0])) { + sprintf(buf,"%s:%s:%s\n", + mapping->uidstr, + mapping->gidstr, + mapping->sidstr); + if (!write(fn,buf,strlen(buf))) + err = AGREED; + printf("%s",buf); + } else + undecided = AGREED; + /* records for both owner and group */ + for (mapping = firstmapping; mapping && !err; + mapping = mapping->next) + if (mapping->defined + && mapping->uidstr[0] && mapping->gidstr[0]) { + sprintf(buf,"%s:%s:%s\n", + mapping->uidstr, + mapping->gidstr, + mapping->sidstr); + if (!write(fn,buf,strlen(buf))) + err = AGREED; + printf("%s",buf); + } else + undecided = AGREED; + done = !err; + close(fn); + if (undecided) { + printf("Undecided :\n"); + for (mapping = firstmapping; mapping; + mapping = mapping->next) + if (!mapping->defined) { + printf(" %s\n", mapping->sidstr); + } + } +#ifndef WIN32 + printf("\n* You will have to move the file \"" MAPFILE "\"\n"); + printf(" to directory \"" MAPDIR "\" after mounting\n"); +#endif + } + } + if (!done) + fprintf(stderr, "* Could not create mapping file \"%s\"\n", fullname); + return (done); +} + +STATIC boolean sanitize(void) +{ + char buf[81]; + boolean ok; + int ownercnt; + int groupcnt; + struct MAPPING *mapping; + struct MAPPING *firstowner; + struct MAPPING *genericgroup; + struct MAPPING *group; + char *sidstr; + + /* count owners and groups */ + /* and find first user, and a generic group */ + ownercnt = 0; + groupcnt = 0; + firstowner = (struct MAPPING*)NULL; + genericgroup = (struct MAPPING*)NULL; + for (mapping=firstmapping; mapping; mapping=mapping->next) { + if (mapping->defined && mapping->uidstr[0]) { + if (!ownercnt) + firstowner = mapping; + ownercnt++; + } + if (mapping->defined && mapping->gidstr[0] && !mapping->uidstr[0]) { + groupcnt++; + } + if (!mapping->defined && isgenericgroup(mapping->sidstr)) { + genericgroup = mapping; + } + } +#ifdef WIN32 + /* no user defined, on Windows, suggest a mapping */ + /* based on account currently used */ + if (!ownercnt && currentwinname && currentsid) { + char *owner; + char *p; + + printf("\nYou have defined no file owner,\n"); + printf(" please enter the Linux login which should be mapped\n"); + printf(" to account you are currently using\n"); + printf(" Linux user ? "); + p = fgets(buf, 80, stdin); + if (p && p[0] && (p[strlen(p) - 1] == '\n')) + p[strlen(p) - 1] = '\0'; + if (p && p[0]) { + firstowner = (struct MAPPING*)malloc(sizeof(struct MAPPING)); + owner = (char*)malloc(strlen(p) + 1); + if (firstowner && owner) { + strcpy(owner, p); + firstowner->next = firstmapping; + firstowner->uidstr = owner; + firstowner->gidstr = ""; + firstowner->sidstr = decodesid(currentsid); + firstowner->sid = currentsid; + firstmapping = firstowner; + ownercnt++; + /* prefer a generic group with the same authorities */ + for (mapping=firstmapping; mapping; + mapping=mapping->next) + if (!mapping->defined + && isgenericgroup(mapping->sidstr) + && !memcmp(firstowner->sidstr, + mapping->sidstr, + strlen(mapping->sidstr)-3)) + genericgroup = mapping; + } + } + } +#endif + if (ownercnt) { + /* + * No group was selected, but there were a generic group + * insist in using it, associated to the first user + */ + if (!groupcnt) { + printf("\nYou have defined no group, this can cause problems\n"); + printf("Do you accept defining a standard group ?\n"); + if (!fgets(buf,80,stdin) + || ((buf[0] != 'n') + && (buf[0] != 'N'))) { + if (genericgroup) { + genericgroup->uidstr = ""; + genericgroup->gidstr = firstowner->uidstr; + genericgroup->defined = AGREED; + } else { + group = (struct MAPPING*) + malloc(sizeof(struct MAPPING)); + sidstr = decodesid( + makegroupsid(firstowner->sid)); + if (group && sidstr) { + group->uidstr = ""; + group->gidstr = firstowner-> + uidstr; + group->sidstr = sidstr; + group->defined = AGREED; + group->next = firstmapping; + firstmapping = group; + } + } + } + } + ok = AGREED; + } else { + printf("\nYou have defined no user, no mapping can be built\n"); + ok = DENIED; + } + + return (ok); +} + +STATIC boolean checkoptions(int argc, char *argv[], boolean silent) +{ + boolean err; +#ifdef WIN32 + int xarg; + const char *pvol; + + if (silent) + err = (argc != 1); + else { + err = (argc < 2); + for (xarg=1; (xarg= 'A') && (pvol[0] <= 'Z')) + || ((pvol[0] >= 'a') && (pvol[0] <= 'z'))); + } + } + } + if (err) { + fprintf(stderr, "Usage : usermap [vol1: [vol2: ...]]\n"); + fprintf(stderr, " \"voln\" are the letters of the partition to share with Linux\n"); + fprintf(stderr, " eg C:\n"); + fprintf(stderr, " the Windows system partition should be named first\n"); + } +#else + unused((void*)argv); + unused((void*)&silent); + err = (argc < 2); + if (err) { + fprintf(stderr, "Usage : usermap dev1 [dev2 ...]\n"); + fprintf(stderr, " \"dev.\" are the devices to share with Windows\n"); + fprintf(stderr, " eg /dev/sdb1\n"); + fprintf(stderr, " the devices should not be mounted\n"); + fprintf(stderr, " the Windows system partition should be named first\n"); + } else + if (getuid()) { + fprintf(stderr, "\nSorry, only root can start usermap\n"); + err = AGREED; + } +#endif + return (!err); +} + +STATIC boolean process(int argc, char *argv[]) +{ + boolean ok; + int xarg; + int targ; + + firstmapping = (struct MAPPING *)NULL; + lastmapping = (struct MAPPING *)NULL; + ok = AGREED; +#ifdef WIN32 + for (xarg=1; (xarg 2 ? 2 : 1); + if (!outputmap(argv[targ],MAPDIR)) { + printf("Trying to write file on root directory\n"); + if (outputmap(argv[targ],(const char*)NULL)) { + printf("\nNote : you will have to move the file to directory \"%s\" on Linux\n", + MAPDIR); + } else + ok = DENIED; + } else + ok = DENIED; + } else + ok = DENIED; + return (ok); +} + +int main(int argc, char *argv[]) +{ + boolean ok; + boolean silent; + + silent = !isatty(1); + if (!silent) + welcome(); + if (checkoptions(argc, argv, silent)) { +#ifdef WIN32 + loginname(silent); + if (silent) + ok = minimal(currentsid); + else + ok = process(argc, argv); +#else + if (open_security_api()) { + ok = process(argc,argv); + if (!close_security_api()) ok = DENIED; + } +#endif + } else + ok = DENIED; + if (!ok) + exit(1); + return (0); +} diff --git a/stamp-h1 b/stamp-h1 new file mode 100755 index 0000000..4547fe1 --- a/dev/null +++ b/stamp-h1 @@ -0,0 +1 @@ +timestamp for config.h -- cgit