diff options
Diffstat (limited to 'usr/src/cmd/ntfsprogs')
30 files changed, 0 insertions, 21093 deletions
diff --git a/usr/src/cmd/ntfsprogs/COPYING b/usr/src/cmd/ntfsprogs/COPYING deleted file mode 100644 index d60c31a97a..0000000000 --- a/usr/src/cmd/ntfsprogs/COPYING +++ /dev/null @@ -1,340 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Library General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - <one line to give the program's name and a brief idea of what it does.> - Copyright (C) <year> <name of author> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) 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. - - <signature of Ty Coon>, 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Library General -Public License instead of this License. diff --git a/usr/src/cmd/ntfsprogs/CREDITS b/usr/src/cmd/ntfsprogs/CREDITS deleted file mode 100644 index 29bd3e4c85..0000000000 --- a/usr/src/cmd/ntfsprogs/CREDITS +++ /dev/null @@ -1,40 +0,0 @@ -The following people have contributed directly or indirectly to the Linux-NTFS -project. - -The list is sorted alphabetically, so please keep it this way! - -Please contact <linux-ntfs-dev at lists.sf.net> if you believe someone is -missing or if you prefer not to be listed. - -Alexei Alexandrov <alex_alexandrov at hotmail.com> -Anton Altaparmakov <aia21 at cantab.net> -Albert D. Cahalan <acahalan at cs.uml.edu> -Russ Christensen <rchriste at cs.utah.edu> -Pete Curran <curran at rpi.edu> -Mario Emmenlauer <mario at emmenlauer.de> -Andras Erdei <ccg at freemail.hu> -Matthew J. Fanto <mattjf at uncompiled.com> -Yuval Fledel <yuvalfl at gmail.com> -Marcin GibuÅ‚a <m.gibula at conecto.pl> -Christophe Grenier <grenier at cgsecurity.org> -Csaba Henk <csaba.henk at creo.hu> -Ian Jackson <ian at davenant.greenend.org.uk> -Max Khon <fjoe at samodelkin.net> -Carmelo Kintana <kintana at berkeley.edu> -Jan Kratochvil <project-captive at jankratochvil.net> -Lode Leroy <lode_leroy at hotmail.com> -David MartÃnez Moreno <ender at debian.org> -Giang Nguyen <cauthu at hotmail.com> -Leonard NorrgÃ¥rd <vinsci at nic.funet.fi> -Holger Ohmacht <holger.ohmacht at web.de> -Per Olofsson <pelle at dsv.su.se> -Yura Pakhuchiy <pakhuchiy at gmail.com> -Yuri Per <yuri at acronis.com> -Richard Russon <ntfs at flatcap.org> -Erik Sørnes <erso1970 at yahoo.no> -Szabolcs Szakacsits <szaka at sienet.hu> -zhanglinbao <zhanglinbao2000 at 163.com> - -Configuration, compilation and installation system are originally based on -numerous different GNU and Gnome utilities and libraries so "Many thanks!" -to all the people who have participated in their creation! diff --git a/usr/src/cmd/ntfsprogs/Makefile b/usr/src/cmd/ntfsprogs/Makefile deleted file mode 100644 index 26ffffe100..0000000000 --- a/usr/src/cmd/ntfsprogs/Makefile +++ /dev/null @@ -1,160 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License (the "License"). -# You may not use this file except in compliance with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# - -# -# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. -# - -MKNTFS= mkntfs -NTFSCAT= ntfscat -NTFSCLONE= ntfsclone -NTFSCLUSTER= ntfscluster -NTFSCMP= ntfscmp -NTFSCP= ntfscp -NTFSFIX= ntfsfix -NTFSINFO= ntfsinfo -NTFSLABEL= ntfslabel -NTFSLS= ntfsls -NTFSRESIZE= ntfsresize -NTFSUNDELETE= ntfsundelete - -include ../Makefile.cmd - -C99MODE= $(C99_ENABLE) -CERRWARN += -erroff=E_ATTRIBUTE_PARAM_UNDEFINED -CERRWARN += -erroff=E_ENUM_VAL_OVERFLOWS_INT_MAX -CERRWARN += -erroff=E_STRUCT_DERIVED_FROM_FLEX_MBR - -CPPFLAGS += -DHAVE_CONFIG_H \ - -I. \ - -I../../lib/libntfs/common/include/ntfs - -MKNTFSOBJS= attrdef.o boot.o sd.o mkntfs.o utils.o -NTFSCATOBJS= ntfscat.o utils.o -NTFSCLONEOBJS= ntfsclone.o utils.o -NTFSCLUSTEROBJS=ntfscluster.o cluster.o utils.o -NTFSCMPOBJS= ntfscmp.o utils.o -NTFSCPOBJS= ntfscp.o utils.o -NTFSFIXOBJS= ntfsfix.o utils.o -NTFSINFOOBJS= ntfsinfo.o utils.o -NTFSLABELOBJS= ntfslabel.o utils.o -NTFSLSOBJS= ntfsls.o utils.o -NTFSRESIZEOBJS= ntfsresize.o utils.o -NTFSUNDELETEOBJS=ntfsundelete.o utils.o - -LDLIBS += ../../lib/libntfs/i386/libntfs.so.10 - -ROOTPROG= $(MKNTFS:%=$(ROOTUSRSBIN)/%) \ - $(NTFSCAT:%=$(ROOTUSRSBIN)/%) \ - $(NTFSCLONE:%=$(ROOTUSRSBIN)/%) \ - $(NTFSCLUSTER:%=$(ROOTUSRSBIN)/%) \ - $(NTFSCMP:%=$(ROOTUSRSBIN)/%) \ - $(NTFSCP:%=$(ROOTUSRSBIN)/%) \ - $(NTFSFIX:%=$(ROOTUSRSBIN)/%) \ - $(NTFSINFO:%=$(ROOTUSRSBIN)/%) \ - $(NTFSLABEL:%=$(ROOTUSRSBIN)/%) \ - $(NTFSLS:%=$(ROOTUSRSBIN)/%) \ - $(NTFSRESIZE:%=$(ROOTUSRSBIN)/%) \ - $(NTFSUNDELETE:%=$(ROOTUSRSBIN)/%) - -.KEEP_STATE: -all: $(MKNTFS) $(NTFSCAT) $(NTFSCLONE) $(NTFSCLUSTER) \ - $(NTFSCMP) $(NTFSCP) $(NTFSFIX) $(NTFSINFO) \ - $(NTFSLABEL) $(NTFSLS) $(NTFSRESIZE) $(NTFSUNDELETE) - -all install: THIRDPARTYLICENSE - -CLOBBERFILES += THIRDPARTYLICENSE - -THIRDPARTYLICENSE: $(SRC)/common/GPLDISCLAIMER COPYING - $(RM) $@ - $(CAT) $(SRC)/common/GPLDISCLAIMER COPYING > $@ - -$(MKNTFS): $(MKNTFSOBJS) - $(LINK.c) -o $(MKNTFS) $(MKNTFSOBJS) $(LDLIBS) -luuid - $(POST_PROCESS) - -$(NTFSCAT): $(NTFSCATOBJS) - $(LINK.c) -o $(NTFSCAT) $(NTFSCATOBJS) $(LDLIBS) - $(POST_PROCESS) - -$(NTFSCLONE): $(NTFSCLONEOBJS) - $(LINK.c) -o $(NTFSCLONE) $(NTFSCLONEOBJS) $(LDLIBS) - $(POST_PROCESS) - -$(NTFSCLUSTER): $(NTFSCLUSTEROBJS) - $(LINK.c) -o $(NTFSCLUSTER) $(NTFSCLUSTEROBJS) $(LDLIBS) - $(POST_PROCESS) - -$(NTFSCMP): $(NTFSCMPOBJS) - $(LINK.c) -o $(NTFSCMP) $(NTFSCMPOBJS) $(LDLIBS) - $(POST_PROCESS) - -$(NTFSCP): $(NTFSCPOBJS) - $(LINK.c) -o $(NTFSCP) $(NTFSCPOBJS) $(LDLIBS) - $(POST_PROCESS) - -$(NTFSFIX): $(NTFSFIXOBJS) - $(LINK.c) -o $(NTFSFIX) $(NTFSFIXOBJS) $(LDLIBS) - $(POST_PROCESS) - -$(NTFSINFO): $(NTFSINFOOBJS) - $(LINK.c) -o $(NTFSINFO) $(NTFSINFOOBJS) $(LDLIBS) - $(POST_PROCESS) - -$(NTFSLABEL): $(NTFSLABELOBJS) - $(LINK.c) -o $(NTFSLABEL) $(NTFSLABELOBJS) $(LDLIBS) - $(POST_PROCESS) - -$(NTFSLS): $(NTFSLSOBJS) - $(LINK.c) -o $(NTFSLS) $(NTFSLSOBJS) $(LDLIBS) - $(POST_PROCESS) - -$(NTFSRESIZE): $(NTFSRESIZEOBJS) - $(LINK.c) -o $(NTFSRESIZE) $(NTFSRESIZEOBJS) $(LDLIBS) - $(POST_PROCESS) - -$(NTFSUNDELETE): $(NTFSUNDELETEOBJS) - $(LINK.c) -o $(NTFSUNDELETE) $(NTFSUNDELETEOBJS) $(LDLIBS) - $(POST_PROCESS) - -install: all $(ROOTPROG) - -clean: - $(RM) $(MKNTFS) $(MKNTFSOBJS) \ - $(NTFSCAT) $(NTFSCATOBJS) \ - $(NTFSCLONE) $(NTFSCLONEOBJS) \ - $(NTFSCLUSTER) $(NTFSCLUSTEROBJS) \ - $(NTFSCMP) $(NTFSCMPOBJS) \ - $(NTFSCP) $(NTFSCPOBJS) \ - $(NTFSFIX) $(NTFSFIXOBJS) \ - $(NTFSINFO) $(NTFSINFOOBJS) \ - $(NTFSLABEL) $(NTFSLABELOBJS) \ - $(NTFSLS) $(NTFSLSOBJS) \ - $(NTFSRESIZE) $(NTFSRESIZEOBJS) \ - $(NTFSUNDELETE) $(NTFSUNDELETEOBJS) - -# -# This open source is exempted from lint -# -lint: - -include ../Makefile.targ diff --git a/usr/src/cmd/ntfsprogs/README b/usr/src/cmd/ntfsprogs/README deleted file mode 100644 index 58c4aec793..0000000000 --- a/usr/src/cmd/ntfsprogs/README +++ /dev/null @@ -1,9 +0,0 @@ -This is the Solaris ON port of ntfsprogs v2.0.0 -Please see http://www.linux-ntfs.org/ for more information. - -ntfsprogs has been broken into two pieces: src/lib/libntfs and src/cmd/ntfsprogs - -The Makefiles have all been replaced by ON Makefiles. - -This directory contains the necessary contents of ntfsprogs-2.0.0/ntfsprogs -ntfsmount is missing until FUSE has been integrated into ON. diff --git a/usr/src/cmd/ntfsprogs/THIRDPARTYLICENSE.descrip b/usr/src/cmd/ntfsprogs/THIRDPARTYLICENSE.descrip deleted file mode 100644 index 6d2fc7f55a..0000000000 --- a/usr/src/cmd/ntfsprogs/THIRDPARTYLICENSE.descrip +++ /dev/null @@ -1 +0,0 @@ -ntfsprogs - NTFS utilities diff --git a/usr/src/cmd/ntfsprogs/attrdef.c b/usr/src/cmd/ntfsprogs/attrdef.c deleted file mode 100644 index 36501e5c27..0000000000 --- a/usr/src/cmd/ntfsprogs/attrdef.c +++ /dev/null @@ -1,168 +0,0 @@ -#include "attrdef.h" - -/** - * attrdef_ntfs3x_array - */ -const unsigned char attrdef_ntfs3x_array[2560] = { -0x24, 0x00, 0x53, 0x00, 0x54, 0x00, 0x41, 0x00, 0x4E, 0x00, 0x44, 0x00, 0x41, 0x00, 0x52, 0x00, -0x44, 0x00, 0x5F, 0x00, 0x49, 0x00, 0x4E, 0x00, 0x46, 0x00, 0x4F, 0x00, 0x52, 0x00, 0x4D, 0x00, -0x41, 0x00, 0x54, 0x00, 0x49, 0x00, 0x4F, 0x00, 0x4E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, -0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x24, 0x00, 0x41, 0x00, 0x54, 0x00, 0x54, 0x00, 0x52, 0x00, 0x49, 0x00, 0x42, 0x00, 0x55, 0x00, -0x54, 0x00, 0x45, 0x00, 0x5F, 0x00, 0x4C, 0x00, 0x49, 0x00, 0x53, 0x00, 0x54, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, -0x24, 0x00, 0x46, 0x00, 0x49, 0x00, 0x4C, 0x00, 0x45, 0x00, 0x5F, 0x00, 0x4E, 0x00, 0x41, 0x00, -0x4D, 0x00, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, -0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x24, 0x00, 0x4F, 0x00, 0x42, 0x00, 0x4A, 0x00, 0x45, 0x00, 0x43, 0x00, 0x54, 0x00, 0x5F, 0x00, -0x49, 0x00, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x24, 0x00, 0x53, 0x00, 0x45, 0x00, 0x43, 0x00, 0x55, 0x00, 0x52, 0x00, 0x49, 0x00, 0x54, 0x00, -0x59, 0x00, 0x5F, 0x00, 0x44, 0x00, 0x45, 0x00, 0x53, 0x00, 0x43, 0x00, 0x52, 0x00, 0x49, 0x00, -0x50, 0x00, 0x54, 0x00, 0x4F, 0x00, 0x52, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, -0x24, 0x00, 0x56, 0x00, 0x4F, 0x00, 0x4C, 0x00, 0x55, 0x00, 0x4D, 0x00, 0x45, 0x00, 0x5F, 0x00, -0x4E, 0x00, 0x41, 0x00, 0x4D, 0x00, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, -0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x24, 0x00, 0x56, 0x00, 0x4F, 0x00, 0x4C, 0x00, 0x55, 0x00, 0x4D, 0x00, 0x45, 0x00, 0x5F, 0x00, -0x49, 0x00, 0x4E, 0x00, 0x46, 0x00, 0x4F, 0x00, 0x52, 0x00, 0x4D, 0x00, 0x41, 0x00, 0x54, 0x00, -0x49, 0x00, 0x4F, 0x00, 0x4E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, -0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x24, 0x00, 0x44, 0x00, 0x41, 0x00, 0x54, 0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, -0x24, 0x00, 0x49, 0x00, 0x4E, 0x00, 0x44, 0x00, 0x45, 0x00, 0x58, 0x00, 0x5F, 0x00, 0x52, 0x00, -0x4F, 0x00, 0x4F, 0x00, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, -0x24, 0x00, 0x49, 0x00, 0x4E, 0x00, 0x44, 0x00, 0x45, 0x00, 0x58, 0x00, 0x5F, 0x00, 0x41, 0x00, -0x4C, 0x00, 0x4C, 0x00, 0x4F, 0x00, 0x43, 0x00, 0x41, 0x00, 0x54, 0x00, 0x49, 0x00, 0x4F, 0x00, -0x4E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, -0x24, 0x00, 0x42, 0x00, 0x49, 0x00, 0x54, 0x00, 0x4D, 0x00, 0x41, 0x00, 0x50, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xB0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, -0x24, 0x00, 0x52, 0x00, 0x45, 0x00, 0x50, 0x00, 0x41, 0x00, 0x52, 0x00, 0x53, 0x00, 0x45, 0x00, -0x5F, 0x00, 0x50, 0x00, 0x4F, 0x00, 0x49, 0x00, 0x4E, 0x00, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x24, 0x00, 0x45, 0x00, 0x41, 0x00, 0x5F, 0x00, 0x49, 0x00, 0x4E, 0x00, 0x46, 0x00, 0x4F, 0x00, -0x52, 0x00, 0x4D, 0x00, 0x41, 0x00, 0x54, 0x00, 0x49, 0x00, 0x4F, 0x00, 0x4E, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xD0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, -0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x24, 0x00, 0x45, 0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, -0x24, 0x00, 0x4C, 0x00, 0x4F, 0x00, 0x47, 0x00, 0x47, 0x00, 0x45, 0x00, 0x44, 0x00, 0x5F, 0x00, -0x55, 0x00, 0x54, 0x00, 0x49, 0x00, 0x4C, 0x00, 0x49, 0x00, 0x54, 0x00, 0x59, 0x00, 0x5F, 0x00, -0x53, 0x00, 0x54, 0x00, 0x52, 0x00, 0x45, 0x00, 0x41, 0x00, 0x4D, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; - diff --git a/usr/src/cmd/ntfsprogs/attrdef.h b/usr/src/cmd/ntfsprogs/attrdef.h deleted file mode 100644 index 0c664394e0..0000000000 --- a/usr/src/cmd/ntfsprogs/attrdef.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef _NTFS_ATTRDEF_H_ -#define _NTFS_ATTRDEF_H_ - -extern const unsigned char attrdef_ntfs3x_array[2560]; - -#endif /* _NTFS_ATTRDEF_H_ */ - diff --git a/usr/src/cmd/ntfsprogs/boot.c b/usr/src/cmd/ntfsprogs/boot.c deleted file mode 100644 index 9272be9fb1..0000000000 --- a/usr/src/cmd/ntfsprogs/boot.c +++ /dev/null @@ -1,268 +0,0 @@ -#include "boot.h" - -/** - * boot_array - the first 4136 bytes of $Boot - * - * The first 4136 bytes of $Boot. The rest is just zero. Total 8192 bytes. - */ -const unsigned char boot_array[4136] = { -235, 82, 144, 78, 84, 70, 83, 32, 32, 32, 32, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 250, 51, 192, 142, 208, 188, 0, 124, 251, 104, 192, 7, - 31, 30, 104, 102, 0, 203, 136, 22, 14, 0, 102, 129, 62, 3, 0, 78, - 84, 70, 83, 117, 21, 180, 65, 187, 170, 85, 205, 19, 114, 12, 129, 251, - 85, 170, 117, 6, 247, 193, 1, 0, 117, 3, 233, 210, 0, 30, 131, 236, - 24, 104, 26, 0, 180, 72, 138, 22, 14, 0, 139, 244, 22, 31, 205, 19, -159, 131, 196, 24, 158, 88, 31, 114, 225, 59, 6, 11, 0, 117, 219, 163, - 15, 0, 193, 46, 15, 0, 4, 30, 90, 51, 219, 185, 0, 32, 43, 200, -102, 255, 6, 17, 0, 3, 22, 15, 0, 142, 194, 255, 6, 22, 0, 232, - 64, 0, 43, 200, 119, 239, 184, 0, 187, 205, 26, 102, 35, 192, 117, 45, -102, 129, 251, 84, 67, 80, 65, 117, 36, 129, 249, 2, 1, 114, 30, 22, -104, 7, 187, 22, 104, 112, 14, 22, 104, 9, 0, 102, 83, 102, 83, 102, - 85, 22, 22, 22, 104, 184, 1, 102, 97, 14, 7, 205, 26, 233, 106, 1, -144, 144, 102, 96, 30, 6, 102, 161, 17, 0, 102, 3, 6, 28, 0, 30, -102, 104, 0, 0, 0, 0, 102, 80, 6, 83, 104, 1, 0, 104, 16, 0, -180, 66, 138, 22, 14, 0, 22, 31, 139, 244, 205, 19, 102, 89, 91, 90, -102, 89, 102, 89, 31, 15, 130, 22, 0, 102, 255, 6, 17, 0, 3, 22, - 15, 0, 142, 194, 255, 14, 22, 0, 117, 188, 7, 31, 102, 97, 195, 160, -248, 1, 232, 8, 0, 160, 251, 1, 232, 2, 0, 235, 254, 180, 1, 139, -240, 172, 60, 0, 116, 9, 180, 14, 187, 7, 0, 205, 16, 235, 242, 195, - 13, 10, 65, 32, 100, 105, 115, 107, 32, 114, 101, 97, 100, 32, 101, 114, -114, 111, 114, 32, 111, 99, 99, 117, 114, 114, 101, 100, 0, 13, 10, 66, - 79, 79, 84, 77, 71, 82, 32, 105, 115, 32, 109, 105, 115, 115, 105, 110, -103, 0, 13, 10, 66, 79, 79, 84, 77, 71, 82, 32, 105, 115, 32, 99, -111, 109, 112, 114, 101, 115, 115, 101, 100, 0, 13, 10, 80, 114, 101, 115, -115, 32, 67, 116, 114, 108, 43, 65, 108, 116, 43, 68, 101, 108, 32, 116, -111, 32, 114, 101, 115, 116, 97, 114, 116, 13, 10, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 128, 157, 178, 202, 0, 0, 85, 170, - 7, 0, 66, 0, 79, 0, 79, 0, 84, 0, 77, 0, 71, 0, 82, 0, - 4, 0, 36, 0, 73, 0, 51, 0, 48, 0, 0, 224, 0, 0, 0, 48, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 235, 34, 144, 144, 5, 0, 78, 0, 84, 0, - 76, 0, 68, 0, 82, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 102, 15, 183, 6, 11, 0, -102, 15, 182, 30, 13, 0, 102, 247, 227, 102, 163, 82, 2, 102, 139, 14, - 64, 0, 128, 249, 0, 15, 143, 14, 0, 246, 217, 102, 184, 1, 0, 0, - 0, 102, 211, 224, 235, 8, 144, 102, 161, 82, 2, 102, 247, 225, 102, 163, -102, 2, 102, 15, 183, 30, 11, 0, 102, 51, 210, 102, 247, 243, 102, 163, - 86, 2, 232, 149, 4, 102, 139, 14, 78, 2, 102, 137, 14, 38, 2, 102, - 3, 14, 102, 2, 102, 137, 14, 42, 2, 102, 3, 14, 102, 2, 102, 137, - 14, 46, 2, 102, 3, 14, 102, 2, 102, 137, 14, 62, 2, 102, 3, 14, -102, 2, 102, 137, 14, 70, 2, 102, 184, 144, 0, 0, 0, 102, 139, 14, - 38, 2, 232, 131, 9, 102, 11, 192, 15, 132, 83, 254, 102, 163, 50, 2, -102, 184, 160, 0, 0, 0, 102, 139, 14, 42, 2, 232, 106, 9, 102, 163, - 54, 2, 102, 184, 176, 0, 0, 0, 102, 139, 14, 46, 2, 232, 88, 9, -102, 163, 58, 2, 102, 161, 50, 2, 102, 11, 192, 15, 132, 32, 254, 103, -128, 120, 8, 0, 15, 133, 23, 254, 103, 102, 141, 80, 16, 103, 3, 66, - 4, 103, 102, 15, 182, 72, 12, 102, 137, 14, 114, 2, 103, 102, 139, 72, - 8, 102, 137, 14, 110, 2, 102, 161, 110, 2, 102, 15, 183, 14, 11, 0, -102, 51, 210, 102, 247, 241, 102, 163, 118, 2, 102, 161, 70, 2, 102, 3, - 6, 110, 2, 102, 163, 74, 2, 102, 131, 62, 54, 2, 0, 15, 132, 29, - 0, 102, 131, 62, 58, 2, 0, 15, 132, 196, 253, 102, 139, 30, 58, 2, - 30, 7, 102, 139, 62, 74, 2, 102, 161, 46, 2, 232, 224, 1, 102, 15, -183, 14, 0, 2, 102, 184, 2, 2, 0, 0, 232, 34, 8, 102, 11, 192, - 15, 133, 22, 0, 102, 15, 183, 14, 90, 2, 102, 184, 92, 2, 0, 0, -232, 12, 8, 102, 11, 192, 15, 132, 66, 12, 103, 102, 139, 0, 30, 7, -102, 139, 62, 62, 2, 232, 63, 6, 102, 161, 62, 2, 102, 187, 32, 0, - 0, 0, 102, 185, 0, 0, 0, 0, 102, 186, 0, 0, 0, 0, 232, 228, - 0, 102, 133, 192, 15, 133, 35, 0, 102, 161, 62, 2, 102, 187, 128, 0, - 0, 0, 102, 185, 0, 0, 0, 0, 102, 186, 0, 0, 0, 0, 232, 196, - 0, 102, 11, 192, 15, 133, 68, 0, 233, 241, 11, 102, 51, 210, 102, 185, -128, 0, 0, 0, 102, 161, 62, 2, 232, 202, 8, 102, 11, 192, 15, 132, -218, 11, 30, 7, 102, 139, 62, 62, 2, 232, 219, 5, 102, 161, 62, 2, -102, 187, 128, 0, 0, 0, 102, 185, 0, 0, 0, 0, 102, 186, 0, 0, - 0, 0, 232, 128, 0, 102, 11, 192, 15, 132, 176, 11, 103, 102, 15, 183, - 88, 12, 102, 129, 227, 255, 0, 0, 0, 15, 133, 165, 11, 102, 139, 216, -104, 0, 32, 7, 102, 43, 255, 102, 161, 62, 2, 232, 0, 1, 104, 0, - 32, 7, 102, 43, 255, 102, 161, 62, 2, 232, 172, 10, 138, 22, 14, 0, -184, 232, 3, 142, 192, 141, 54, 11, 0, 43, 192, 104, 0, 32, 80, 203, - 6, 30, 102, 96, 102, 139, 218, 102, 15, 182, 14, 13, 0, 102, 247, 225, -102, 163, 17, 0, 102, 139, 195, 102, 247, 225, 163, 22, 0, 139, 223, 131, -227, 15, 140, 192, 102, 193, 239, 4, 3, 199, 80, 7, 232, 51, 252, 102, - 97, 144, 31, 7, 195, 103, 3, 64, 20, 103, 102, 131, 56, 255, 15, 132, - 76, 0, 103, 102, 57, 24, 15, 133, 51, 0, 102, 11, 201, 15, 133, 10, - 0, 103, 128, 120, 9, 0, 15, 133, 35, 0, 195, 103, 58, 72, 9, 15, -133, 26, 0, 102, 139, 240, 103, 3, 112, 10, 232, 151, 6, 102, 81, 30, - 7, 102, 139, 250, 243, 167, 102, 89, 15, 133, 1, 0, 195, 103, 102, 131, -120, 4, 0, 15, 132, 7, 0, 103, 102, 3, 64, 4, 235, 171, 102, 43, -192, 195, 102, 139, 243, 232, 108, 6, 103, 102, 3, 0, 103, 247, 64, 12, - 2, 0, 15, 133, 52, 0, 103, 102, 141, 80, 16, 103, 58, 74, 64, 15, -133, 24, 0, 103, 102, 141, 114, 66, 232, 73, 6, 102, 81, 30, 7, 102, -139, 251, 243, 167, 102, 89, 15, 133, 1, 0, 195, 103, 131, 120, 8, 0, - 15, 132, 6, 0, 103, 3, 64, 8, 235, 194, 102, 51, 192, 195, 103, 128, -123, 8, 0, 15, 133, 28, 0, 6, 30, 102, 96, 103, 102, 141, 83, 16, -103, 102, 139, 10, 102, 139, 243, 103, 3, 114, 4, 243, 164, 102, 97, 144, - 31, 7, 195, 102, 80, 103, 102, 141, 83, 16, 102, 133, 192, 15, 133, 10, - 0, 103, 102, 139, 74, 8, 102, 65, 235, 17, 144, 103, 102, 139, 66, 24, -102, 51, 210, 102, 247, 54, 82, 2, 102, 139, 200, 102, 43, 192, 102, 94, -232, 1, 0, 195, 6, 30, 102, 96, 103, 128, 123, 8, 1, 15, 132, 3, - 0, 233, 107, 251, 102, 131, 249, 0, 15, 133, 6, 0, 102, 97, 144, 31, - 7, 195, 102, 83, 102, 80, 102, 81, 102, 86, 102, 87, 6, 232, 145, 4, -102, 139, 209, 7, 102, 95, 102, 94, 102, 89, 102, 133, 192, 15, 132, 52, - 0, 102, 59, 202, 15, 141, 3, 0, 102, 139, 209, 232, 130, 254, 102, 43, -202, 102, 139, 218, 102, 139, 194, 102, 15, 182, 22, 13, 0, 102, 247, 226, -102, 15, 183, 22, 11, 0, 102, 247, 226, 102, 3, 248, 102, 88, 102, 3, -195, 102, 91, 235, 159, 102, 133, 246, 15, 132, 3, 251, 102, 81, 102, 87, - 6, 103, 102, 15, 182, 67, 9, 102, 133, 192, 15, 132, 32, 0, 102, 209, -224, 102, 43, 224, 102, 139, 252, 102, 84, 102, 86, 103, 102, 15, 183, 115, - 10, 102, 3, 243, 102, 139, 200, 243, 164, 102, 94, 235, 3, 144, 102, 80, -102, 80, 103, 102, 139, 3, 102, 80, 103, 102, 139, 67, 24, 102, 80, 103, -102, 139, 86, 32, 102, 133, 210, 15, 132, 11, 0, 102, 139, 254, 30, 7, -102, 139, 194, 232, 113, 3, 102, 139, 198, 102, 90, 102, 89, 102, 66, 102, - 81, 102, 86, 232, 63, 6, 102, 133, 192, 15, 132, 146, 250, 102, 94, 102, - 89, 102, 139, 254, 30, 7, 232, 78, 3, 102, 139, 198, 102, 139, 217, 102, - 89, 102, 90, 102, 81, 102, 86, 102, 209, 233, 232, 248, 253, 102, 133, 192, - 15, 132, 107, 250, 102, 94, 102, 89, 102, 3, 225, 7, 102, 95, 102, 89, -102, 139, 208, 102, 88, 102, 91, 102, 139, 218, 233, 245, 254, 6, 30, 102, - 96, 38, 103, 102, 15, 183, 95, 4, 38, 103, 102, 15, 183, 79, 6, 102, - 11, 201, 15, 132, 57, 250, 102, 3, 223, 102, 131, 195, 2, 102, 129, 199, -254, 1, 0, 0, 102, 73, 102, 11, 201, 15, 132, 23, 0, 38, 103, 139, - 3, 38, 103, 137, 7, 102, 131, 195, 2, 102, 129, 199, 0, 2, 0, 0, -102, 73, 235, 226, 102, 97, 144, 31, 7, 195, 6, 30, 102, 96, 102, 184, - 1, 0, 0, 0, 102, 163, 34, 2, 102, 161, 30, 2, 102, 3, 6, 102, - 2, 102, 163, 106, 2, 102, 3, 6, 102, 2, 102, 163, 78, 2, 102, 161, - 48, 0, 102, 15, 182, 30, 13, 0, 102, 247, 227, 102, 139, 30, 78, 2, -102, 137, 7, 102, 163, 17, 0, 131, 195, 4, 102, 161, 86, 2, 102, 137, - 7, 163, 22, 0, 131, 195, 4, 102, 137, 30, 78, 2, 102, 139, 30, 30, - 2, 30, 7, 232, 92, 249, 102, 139, 251, 232, 81, 255, 102, 161, 30, 2, -102, 187, 32, 0, 0, 0, 102, 185, 0, 0, 0, 0, 102, 186, 0, 0, - 0, 0, 232, 16, 253, 102, 11, 192, 15, 132, 25, 1, 102, 139, 216, 30, - 7, 102, 139, 62, 26, 2, 102, 51, 192, 232, 162, 253, 102, 139, 30, 26, - 2, 102, 129, 63, 128, 0, 0, 0, 15, 132, 235, 0, 3, 95, 4, 235, -240, 102, 83, 102, 139, 71, 16, 102, 247, 38, 86, 2, 102, 80, 102, 51, -210, 102, 15, 182, 30, 13, 0, 102, 247, 243, 102, 82, 232, 220, 0, 102, - 11, 192, 15, 132, 57, 249, 102, 139, 14, 86, 2, 102, 15, 182, 30, 13, - 0, 102, 247, 227, 102, 90, 102, 3, 194, 102, 139, 30, 78, 2, 102, 137, - 7, 131, 195, 4, 102, 15, 182, 6, 13, 0, 102, 43, 194, 102, 59, 193, - 15, 134, 3, 0, 102, 139, 193, 102, 137, 7, 102, 43, 200, 102, 90, 15, -132, 117, 0, 102, 3, 194, 102, 80, 102, 51, 210, 102, 15, 182, 30, 13, - 0, 102, 247, 243, 102, 81, 232, 130, 0, 102, 89, 102, 11, 192, 15, 132, -221, 248, 102, 15, 182, 30, 13, 0, 102, 247, 227, 102, 139, 30, 78, 2, -102, 139, 23, 131, 195, 4, 102, 3, 23, 102, 59, 208, 15, 133, 21, 0, -102, 15, 182, 6, 13, 0, 102, 59, 193, 15, 134, 3, 0, 102, 139, 193, -102, 1, 7, 235, 165, 131, 195, 4, 102, 137, 30, 78, 2, 102, 137, 7, -131, 195, 4, 102, 15, 182, 6, 13, 0, 102, 59, 193, 15, 134, 3, 0, -102, 139, 193, 102, 137, 7, 235, 130, 131, 195, 4, 102, 255, 6, 34, 2, -102, 137, 30, 78, 2, 102, 91, 3, 95, 4, 102, 129, 63, 128, 0, 0, - 0, 15, 132, 12, 255, 102, 97, 144, 31, 7, 195, 102, 139, 208, 102, 139, - 14, 34, 2, 102, 139, 54, 106, 2, 102, 3, 54, 102, 2, 102, 82, 102, - 81, 102, 82, 102, 139, 30, 106, 2, 102, 139, 62, 86, 2, 102, 139, 4, -102, 163, 17, 0, 131, 198, 4, 102, 139, 4, 163, 22, 0, 131, 198, 4, - 30, 7, 232, 221, 247, 102, 43, 248, 15, 132, 8, 0, 247, 38, 11, 0, - 3, 216, 235, 217, 102, 139, 62, 106, 2, 30, 7, 232, 191, 253, 102, 161, -106, 2, 102, 187, 128, 0, 0, 0, 102, 185, 0, 0, 0, 0, 102, 139, -209, 232, 129, 251, 102, 11, 192, 15, 132, 244, 247, 102, 139, 216, 102, 88, -102, 86, 232, 44, 1, 102, 94, 102, 11, 192, 15, 132, 5, 0, 102, 91, -102, 91, 195, 102, 89, 102, 90, 226, 132, 102, 51, 192, 195, 6, 30, 102, - 96, 102, 80, 102, 81, 102, 51, 210, 102, 15, 182, 30, 13, 0, 102, 247, -243, 102, 82, 102, 87, 232, 83, 255, 102, 95, 102, 11, 192, 15, 132, 174, -247, 102, 15, 182, 30, 13, 0, 102, 247, 227, 102, 90, 102, 3, 194, 102, -163, 17, 0, 102, 89, 102, 15, 182, 30, 13, 0, 102, 59, 203, 15, 142, - 19, 0, 137, 30, 22, 0, 102, 43, 203, 102, 88, 102, 3, 195, 102, 80, -102, 81, 235, 20, 144, 102, 88, 102, 3, 193, 102, 80, 137, 14, 22, 0, -102, 185, 0, 0, 0, 0, 102, 81, 6, 102, 87, 139, 223, 131, 227, 15, -140, 192, 102, 193, 239, 4, 3, 199, 80, 7, 232, 5, 247, 102, 95, 7, -102, 3, 62, 82, 2, 102, 89, 102, 88, 102, 131, 249, 0, 15, 143, 112, -255, 102, 97, 144, 31, 7, 195, 6, 30, 102, 96, 102, 247, 38, 86, 2, -102, 139, 14, 86, 2, 232, 85, 255, 232, 210, 252, 102, 97, 144, 31, 7, -195, 6, 30, 102, 96, 102, 247, 38, 114, 2, 102, 139, 30, 54, 2, 102, -139, 14, 114, 2, 102, 139, 54, 42, 2, 30, 7, 102, 139, 62, 70, 2, -232, 129, 251, 232, 167, 252, 102, 97, 144, 31, 7, 195, 102, 80, 102, 83, -102, 81, 102, 139, 30, 74, 2, 102, 139, 200, 102, 193, 232, 3, 102, 131, -225, 7, 102, 3, 216, 102, 184, 1, 0, 0, 0, 102, 211, 224, 103, 132, - 3, 15, 132, 4, 0, 248, 235, 2, 144, 249, 102, 89, 102, 91, 102, 88, -195, 103, 128, 123, 8, 1, 15, 132, 4, 0, 102, 43, 192, 195, 103, 102, -141, 115, 16, 103, 102, 139, 86, 8, 102, 59, 194, 15, 135, 11, 0, 103, -102, 139, 22, 102, 59, 194, 15, 131, 4, 0, 102, 43, 192, 195, 103, 3, - 94, 16, 102, 43, 246, 103, 128, 59, 0, 15, 132, 62, 0, 232, 129, 0, -102, 3, 241, 232, 57, 0, 102, 3, 202, 102, 59, 193, 15, 140, 33, 0, -102, 139, 209, 102, 80, 103, 102, 15, 182, 11, 102, 139, 193, 102, 131, 224, - 15, 102, 193, 233, 4, 102, 3, 217, 102, 3, 216, 102, 67, 102, 88, 235, -196, 102, 43, 200, 102, 43, 194, 102, 3, 198, 195, 102, 43, 192, 195, 102, - 43, 201, 103, 138, 11, 128, 225, 15, 102, 131, 249, 0, 15, 133, 4, 0, -102, 43, 201, 195, 102, 83, 102, 82, 102, 3, 217, 103, 102, 15, 190, 19, -102, 73, 102, 75, 102, 131, 249, 0, 15, 132, 13, 0, 102, 193, 226, 8, -103, 138, 19, 102, 75, 102, 73, 235, 235, 102, 139, 202, 102, 90, 102, 91, -195, 102, 83, 102, 82, 102, 43, 210, 103, 138, 19, 102, 131, 226, 15, 102, - 43, 201, 103, 138, 11, 192, 233, 4, 102, 131, 249, 0, 15, 133, 8, 0, -102, 43, 201, 102, 90, 102, 91, 195, 102, 3, 218, 102, 3, 217, 103, 102, - 15, 190, 19, 102, 73, 102, 75, 102, 131, 249, 0, 15, 132, 13, 0, 102, -193, 226, 8, 103, 138, 19, 102, 75, 102, 73, 235, 235, 102, 139, 202, 102, - 90, 102, 91, 195, 102, 11, 201, 15, 133, 1, 0, 195, 102, 81, 102, 86, -103, 131, 62, 97, 15, 140, 12, 0, 103, 131, 62, 122, 15, 143, 4, 0, -103, 131, 46, 32, 102, 131, 198, 2, 226, 230, 102, 94, 102, 89, 195, 102, - 80, 102, 81, 102, 139, 208, 102, 161, 50, 2, 103, 102, 141, 88, 16, 103, - 3, 67, 4, 103, 102, 141, 64, 16, 102, 139, 218, 232, 68, 249, 102, 11, -192, 15, 132, 5, 0, 102, 89, 102, 89, 195, 102, 161, 54, 2, 102, 11, -192, 15, 133, 8, 0, 102, 89, 102, 89, 102, 51, 192, 195, 102, 139, 22, - 54, 2, 103, 102, 141, 82, 16, 103, 102, 139, 66, 24, 102, 51, 210, 102, -247, 54, 110, 2, 102, 51, 246, 102, 80, 102, 86, 102, 88, 102, 94, 102, - 59, 198, 15, 132, 58, 0, 102, 86, 102, 64, 102, 80, 102, 72, 232, 27, -254, 114, 232, 232, 235, 253, 102, 90, 102, 94, 102, 89, 102, 91, 102, 83, -102, 81, 102, 86, 102, 82, 102, 161, 70, 2, 103, 102, 141, 64, 24, 232, -208, 248, 102, 11, 192, 116, 196, 102, 89, 102, 89, 102, 89, 102, 89, 195, -102, 89, 102, 89, 102, 51, 192, 195, 102, 81, 102, 80, 102, 184, 5, 0, - 0, 0, 30, 7, 102, 139, 249, 232, 141, 253, 102, 139, 193, 102, 187, 32, - 0, 0, 0, 102, 185, 0, 0, 0, 0, 102, 186, 0, 0, 0, 0, 232, - 51, 248, 102, 91, 102, 89, 102, 133, 192, 15, 133, 21, 0, 102, 139, 193, -102, 15, 183, 14, 16, 2, 102, 186, 18, 2, 0, 0, 232, 22, 248, 235, - 51, 144, 102, 51, 210, 102, 139, 193, 102, 139, 203, 102, 80, 102, 83, 232, - 35, 0, 102, 91, 102, 95, 102, 11, 192, 15, 132, 23, 0, 30, 7, 232, - 53, 253, 102, 139, 199, 102, 15, 183, 14, 16, 2, 102, 186, 18, 2, 0, - 0, 232, 225, 247, 195, 102, 82, 102, 81, 102, 187, 32, 0, 0, 0, 102, -185, 0, 0, 0, 0, 102, 186, 0, 0, 0, 0, 232, 199, 247, 102, 11, -192, 15, 132, 99, 0, 102, 139, 216, 30, 7, 102, 139, 62, 26, 2, 102, - 51, 192, 232, 89, 248, 30, 7, 102, 139, 30, 26, 2, 102, 89, 102, 90, - 38, 102, 57, 15, 15, 133, 12, 0, 38, 102, 57, 87, 8, 15, 132, 49, - 0, 235, 19, 144, 38, 102, 131, 63, 255, 15, 132, 47, 0, 38, 131, 127, - 4, 0, 15, 132, 38, 0, 38, 102, 15, 183, 71, 4, 3, 216, 139, 195, - 37, 0, 128, 116, 203, 140, 192, 5, 0, 8, 142, 192, 129, 227, 255, 127, -235, 190, 38, 102, 139, 71, 16, 195, 102, 89, 102, 90, 102, 51, 192, 195, -102, 80, 102, 81, 102, 139, 199, 102, 193, 232, 4, 6, 89, 3, 200, 81, - 7, 102, 131, 231, 15, 102, 89, 102, 88, 195, 96, 6, 190, 189, 13, 191, - 0, 32, 30, 7, 185, 13, 0, 144, 243, 165, 7, 97, 195, 1, 35, 69, -103, 137, 171, 205, 239, 254, 220, 186, 152, 118, 84, 50, 16, 240, 225, 210, -195, 0, 0, 0, 0, 32, 32, 96, 139, 54, 24, 32, 38, 138, 5, 136, - 4, 71, 70, 102, 255, 6, 20, 32, 129, 254, 96, 32, 117, 6, 232, 91, - 0, 190, 32, 32, 226, 230, 137, 54, 24, 32, 97, 195, 102, 96, 139, 54, - 24, 32, 176, 128, 136, 4, 70, 50, 192, 129, 254, 96, 32, 117, 6, 232, - 58, 0, 190, 32, 32, 129, 254, 88, 32, 117, 233, 102, 51, 192, 102, 163, - 88, 32, 102, 161, 20, 32, 102, 193, 224, 3, 102, 15, 200, 102, 163, 92, - 32, 232, 24, 0, 187, 0, 32, 102, 139, 7, 102, 15, 200, 102, 137, 7, -131, 195, 4, 129, 251, 52, 32, 117, 238, 102, 97, 195, 102, 96, 187, 32, - 32, 102, 139, 7, 102, 15, 200, 102, 137, 7, 131, 195, 4, 129, 251, 96, - 32, 117, 238, 187, 0, 32, 102, 139, 15, 102, 139, 87, 4, 102, 139, 119, - 8, 102, 139, 127, 12, 102, 139, 111, 16, 187, 32, 32, 199, 6, 26, 32, - 48, 15, 198, 6, 28, 32, 20, 144, 83, 139, 30, 26, 32, 255, 23, 102, - 3, 71, 2, 91, 102, 3, 232, 102, 3, 47, 102, 139, 193, 102, 193, 192, - 5, 102, 3, 197, 102, 139, 239, 102, 139, 254, 102, 139, 242, 102, 193, 198, - 30, 102, 139, 209, 102, 139, 200, 102, 139, 7, 102, 51, 71, 8, 102, 51, - 71, 32, 102, 51, 71, 52, 102, 209, 192, 102, 137, 71, 64, 131, 195, 4, -254, 14, 28, 32, 117, 178, 131, 6, 26, 32, 6, 129, 62, 26, 32, 72, - 15, 117, 159, 187, 0, 32, 102, 1, 15, 102, 1, 87, 4, 102, 1, 119, - 8, 102, 1, 127, 12, 102, 1, 111, 16, 102, 97, 195, 102, 139, 198, 102, - 51, 199, 102, 35, 194, 102, 51, 199, 195, 102, 139, 194, 102, 51, 198, 102, - 51, 199, 195, 102, 83, 102, 139, 194, 102, 35, 198, 102, 139, 218, 102, 35, -223, 102, 11, 195, 102, 139, 222, 102, 35, 223, 102, 11, 195, 102, 91, 195, -252, 14, 153, 121, 130, 90, 9, 15, 161, 235, 217, 110, 19, 15, 220, 188, - 27, 143, 9, 15, 214, 193, 98, 202, 6, 30, 102, 96, 102, 51, 219, 184, - 0, 187, 205, 26, 102, 35, 192, 15, 133, 187, 0, 102, 129, 251, 84, 67, - 80, 65, 15, 133, 176, 0, 129, 249, 2, 1, 15, 130, 168, 0, 102, 97, -144, 31, 7, 6, 30, 102, 96, 103, 128, 123, 8, 0, 15, 133, 12, 0, -103, 102, 141, 83, 16, 103, 102, 139, 10, 235, 37, 144, 103, 102, 141, 83, - 16, 103, 102, 139, 74, 40, 102, 129, 249, 0, 0, 8, 0, 15, 131, 12, - 0, 103, 102, 139, 66, 44, 102, 35, 192, 15, 132, 3, 0, 102, 51, 201, - 14, 31, 232, 245, 253, 102, 35, 201, 15, 132, 50, 0, 102, 186, 0, 128, - 0, 0, 102, 59, 202, 15, 134, 31, 0, 102, 43, 202, 6, 102, 81, 102, - 87, 102, 82, 102, 139, 202, 232, 183, 253, 232, 251, 253, 102, 90, 102, 95, -102, 89, 7, 102, 3, 250, 235, 218, 232, 165, 253, 232, 233, 253, 232, 11, -254, 14, 7, 102, 187, 84, 67, 80, 65, 102, 191, 0, 32, 0, 0, 102, -185, 20, 0, 0, 0, 102, 184, 7, 187, 0, 0, 102, 186, 10, 0, 0, - 0, 102, 51, 246, 205, 26, 102, 97, 144, 31, 7, 195, 160, 249, 1, 233, - 64, 241, 160, 250, 1, 233, 58, 241 -}; diff --git a/usr/src/cmd/ntfsprogs/boot.h b/usr/src/cmd/ntfsprogs/boot.h deleted file mode 100644 index 45d79927f4..0000000000 --- a/usr/src/cmd/ntfsprogs/boot.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef _NTFS_BOOT_H_ -#define _NTFS_BOOT_H_ - -extern const unsigned char boot_array[4136]; - -#endif /* _NTFS_BOOT_H_ */ - diff --git a/usr/src/cmd/ntfsprogs/cluster.c b/usr/src/cmd/ntfsprogs/cluster.c deleted file mode 100644 index 59d3fe7e5b..0000000000 --- a/usr/src/cmd/ntfsprogs/cluster.c +++ /dev/null @@ -1,119 +0,0 @@ -/** - * cluster - Part of the Linux-NTFS project. - * - * Copyright (c) 2002-2003 Richard Russon - * - * This function will locate the owner of any given sector or cluster range. - * - * 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 Linux-NTFS - * 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_STDIO_H -#include <stdio.h> -#endif -#ifdef HAVE_STDLIB_H -#include <stdlib.h> -#endif -#ifdef HAVE_STRING_H -#include <string.h> -#endif - -#include "compat.h" -#include "cluster.h" -#include "utils.h" -#include "logging.h" - -/** - * cluster_find - */ -int cluster_find(ntfs_volume *vol, LCN c_begin, LCN c_end, cluster_cb *cb, void *data) -{ - int j; - int result = -1; - struct mft_search_ctx *m_ctx = NULL; - ntfs_attr_search_ctx *a_ctx = NULL; - ATTR_RECORD *rec; - runlist *runs; - - if (!vol || !cb) - return -1; - - m_ctx = mft_get_search_ctx(vol); - m_ctx->flags_search = FEMR_IN_USE | FEMR_BASE_RECORD; - - while (mft_next_record(m_ctx) == 0) { - - if (!(m_ctx->flags_match & FEMR_BASE_RECORD)) - continue; - - ntfs_log_verbose("Inode: %llu\n", (unsigned long long) - m_ctx->inode->mft_no); - - a_ctx = ntfs_attr_get_search_ctx(m_ctx->inode, NULL); - - while ((rec = find_attribute(AT_UNUSED, a_ctx))) { - - if (!rec->non_resident) { - ntfs_log_verbose("0x%02x skipped - attr is resident\n", a_ctx->attr->type); - continue; - } - - runs = ntfs_mapping_pairs_decompress(vol, a_ctx->attr, NULL); - if (!runs) { - ntfs_log_error("Couldn't read the data runs.\n"); - goto done; - } - - ntfs_log_verbose("\t[0x%02X]\n", a_ctx->attr->type); - - ntfs_log_verbose("\t\tVCN\tLCN\tLength\n"); - for (j = 0; runs[j].length > 0; j++) { - LCN a_begin = runs[j].lcn; - LCN a_end = a_begin + runs[j].length - 1; - - if (a_begin < 0) - continue; // sparse, discontiguous, etc - - ntfs_log_verbose("\t\t%lld\t%lld-%lld (%lld)\n", - (long long)runs[j].vcn, - (long long)runs[j].lcn, - (long long)(runs[j].lcn + - runs[j].length - 1), - (long long)runs[j].length); - //dprint list - - if ((a_begin > c_end) || (a_end < c_begin)) - continue; // before or after search range - - if ((*cb) (m_ctx->inode, a_ctx->attr, runs+j, data)) - return 1; - } - } - - ntfs_attr_put_search_ctx(a_ctx); - a_ctx = NULL; - } - - result = 0; -done: - ntfs_attr_put_search_ctx(a_ctx); - mft_put_search_ctx(m_ctx); - - return result; -} - diff --git a/usr/src/cmd/ntfsprogs/cluster.h b/usr/src/cmd/ntfsprogs/cluster.h deleted file mode 100644 index 4bc18276a5..0000000000 --- a/usr/src/cmd/ntfsprogs/cluster.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * cluster - Part of the Linux-NTFS project. - * - * Copyright (c) 2003 Richard Russon - * - * This function will locate the owner of any given sector or cluster range. - * - * 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 Linux-NTFS - * 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 _CLUSTER_H_ -#define _CLUSTER_H_ - -#include "types.h" -#include "volume.h" - -typedef struct { - int x; -} ntfs_cluster; - -typedef int (cluster_cb)(ntfs_inode *ino, ATTR_RECORD *attr, runlist_element *run, void *data); - -int cluster_find(ntfs_volume *vol, LCN c_begin, LCN c_end, cluster_cb *cb, void *data); - -#endif /* _CLUSTER_H_ */ - diff --git a/usr/src/cmd/ntfsprogs/mkntfs.c b/usr/src/cmd/ntfsprogs/mkntfs.c deleted file mode 100644 index e23f6a7848..0000000000 --- a/usr/src/cmd/ntfsprogs/mkntfs.c +++ /dev/null @@ -1,4748 +0,0 @@ -/** - * mkntfs - Part of the Linux-NTFS project. - * - * Copyright (c) 2000-2007 Anton Altaparmakov - * Copyright (c) 2001-2005 Richard Russon - * Copyright (c) 2002-2006 Szabolcs Szakacsits - * Copyright (c) 2005 Erik Sornes - * Copyright (c) 2007 Yura Pakhuchiy - * - * This utility will create an NTFS 1.2 or 3.1 volume on a user - * specified (block) device. - * - * Some things (option handling and determination of mount status) have been - * adapted from e2fsprogs-1.19 and lib/ext2fs/ismounted.c and misc/mke2fs.c in - * particular. - * - * 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 Linux-NTFS source - * 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 <unistd.h> -#endif -#ifdef HAVE_STDLIB_H -#include <stdlib.h> -#endif -#ifdef HAVE_STDIO_H -#include <stdio.h> -#endif -#ifdef HAVE_STDARG_H -#include <stdarg.h> -#endif -#ifdef HAVE_STRING_H -#include <string.h> -#endif -#ifdef HAVE_ERRNO_H -#include <errno.h> -#endif -#ifdef HAVE_TIME_H -#include <time.h> -#endif -#ifdef HAVE_SYS_STAT_H -#include <sys/stat.h> -#endif -#ifdef HAVE_FCNTL_H -#include <fcntl.h> -#endif -#ifdef HAVE_LIMITS_H -#include <limits.h> -#endif -#ifdef HAVE_LIBGEN_H -#include <libgen.h> -#endif -#ifdef ENABLE_UUID -#include <uuid/uuid.h> -#endif - - -#ifdef HAVE_GETOPT_H -#include <getopt.h> -#else - extern char *optarg; - extern int optind; -#endif - -#ifdef HAVE_LINUX_MAJOR_H -# include <linux/major.h> -# ifndef MAJOR -# define MAJOR(dev) ((dev) >> 8) -# define MINOR(dev) ((dev) & 0xff) -# endif -# ifndef IDE_DISK_MAJOR -# ifndef IDE0_MAJOR -# define IDE0_MAJOR 3 -# define IDE1_MAJOR 22 -# define IDE2_MAJOR 33 -# define IDE3_MAJOR 34 -# define IDE4_MAJOR 56 -# define IDE5_MAJOR 57 -# define IDE6_MAJOR 88 -# define IDE7_MAJOR 89 -# define IDE8_MAJOR 90 -# define IDE9_MAJOR 91 -# endif -# define IDE_DISK_MAJOR(M) \ - ((M) == IDE0_MAJOR || (M) == IDE1_MAJOR || \ - (M) == IDE2_MAJOR || (M) == IDE3_MAJOR || \ - (M) == IDE4_MAJOR || (M) == IDE5_MAJOR || \ - (M) == IDE6_MAJOR || (M) == IDE7_MAJOR || \ - (M) == IDE8_MAJOR || (M) == IDE9_MAJOR) -# endif -# ifndef SCSI_DISK_MAJOR -# ifndef SCSI_DISK0_MAJOR -# define SCSI_DISK0_MAJOR 8 -# define SCSI_DISK1_MAJOR 65 -# define SCSI_DISK7_MAJOR 71 -# endif -# define SCSI_DISK_MAJOR(M) \ - ((M) == SCSI_DISK0_MAJOR || \ - ((M) >= SCSI_DISK1_MAJOR && \ - (M) <= SCSI_DISK7_MAJOR)) -# endif -#endif - -#include "compat.h" -#include "security.h" -#include "types.h" -#include "attrib.h" -#include "bitmap.h" -#include "bootsect.h" -#include "device.h" -#include "dir.h" -#include "mft.h" -#include "mst.h" -#include "runlist.h" -#include "utils.h" -#include "ntfstime.h" -#include "sd.h" -#include "boot.h" -#include "attrdef.h" -#include "version.h" -#include "logging.h" -#include "support.h" -#include "unistr.h" - -#ifdef NO_NTFS_DEVICE_DEFAULT_IO_OPS -#error "No default device io operations! Cannot build mkntfs. \ -You need to run ./configure without the --disable-default-device-io-ops \ -switch if you want to be able to build the NTFS utilities." -#endif - -/* Page size on ia32. Can change to 8192 on Alpha. */ -#define NTFS_PAGE_SIZE 4096 - -static char EXEC_NAME[] = "mkntfs"; - -/** - * global variables - */ -static u8 *g_buf = NULL; -static int g_mft_bitmap_byte_size = 0; -static u8 *g_mft_bitmap = NULL; -static int g_lcn_bitmap_byte_size = 0; -static u8 *g_lcn_bitmap = NULL; -static runlist *g_rl_mft = NULL; -static runlist *g_rl_mft_bmp = NULL; -static runlist *g_rl_mftmirr = NULL; -static runlist *g_rl_logfile = NULL; -static runlist *g_rl_boot = NULL; -static runlist *g_rl_bad = NULL; -static INDEX_ALLOCATION *g_index_block = NULL; -static ntfs_volume *g_vol = NULL; -static int g_mft_size = 0; -static long long g_mft_lcn = 0; /* lcn of $MFT, $DATA attribute */ -static long long g_mftmirr_lcn = 0; /* lcn of $MFTMirr, $DATA */ -static long long g_logfile_lcn = 0; /* lcn of $LogFile, $DATA */ -static int g_logfile_size = 0; /* in bytes, determined from volume_size */ -static long long g_mft_zone_end = 0; /* Determined from volume_size and mft_zone_multiplier, in clusters */ -static long long g_num_bad_blocks = 0; /* Number of bad clusters */ -static long long *g_bad_blocks = NULL; /* Array of bad clusters */ - -/** - * struct mkntfs_options - */ -static struct mkntfs_options { - char *dev_name; /* Name of the device, or file, to use */ - BOOL enable_compression; /* -C, enables compression of all files on the volume by default. */ - BOOL quick_format; /* -f or -Q, fast format, don't zero the volume first. */ - BOOL force; /* -F, force fs creation. */ - long heads; /* -H, number of heads on device */ - BOOL disable_indexing; /* -I, disables indexing of file contents on the volume by default. */ - BOOL no_action; /* -n, do not write to device, only display what would be done. */ - long long part_start_sect; /* -p, start sector of partition on parent device */ - long sector_size; /* -s, in bytes, power of 2, default is 512 bytes. */ - long sectors_per_track; /* -S, number of sectors per track on device */ - BOOL use_epoch_time; /* -T, fake the time to be 00:00:00 UTC, Jan 1, 1970. */ - long mft_zone_multiplier; /* -z, value from 1 to 4. Default is 1. */ - long long num_sectors; /* size of device in sectors */ - long cluster_size; /* -c, format with this cluster-size */ - char *label; /* -L, volume label */ -} opts; - - -/** - * mkntfs_license - */ -static void mkntfs_license(void) -{ - ntfs_log_info("%s", ntfs_gpl); -} - -/** - * mkntfs_usage - */ -static void mkntfs_usage(void) -{ - ntfs_log_info("\nUsage: %s [options] device [number-of-sectors]\n" -"\n" -"Basic options:\n" -" -f, --fast Perform a quick format\n" -" -Q, --quick Perform a quick format\n" -" -L, --label STRING Set the volume label\n" -" -C, --enable-compression Enable compression on the volume\n" -" -I, --no-indexing Disable indexing on the volume\n" -" -n, --no-action Do not write to disk\n" -"\n" -"Advanced options:\n" -" -c, --cluster-size BYTES Specify the cluster size for the volume\n" -" -s, --sector-size BYTES Specify the sector size for the device\n" -" -p, --partition-start SECTOR Specify the partition start sector\n" -" -H, --heads NUM Specify the number of heads\n" -" -S, --sectors-per-track NUM Specify the number of sectors per track\n" -" -z, --mft-zone-multiplier NUM Set the MFT zone multiplier\n" -" -T, --zero-time Fake the time to be 00:00 UTC, Jan 1, 1970\n" -" -F, --force Force execution despite errors\n" -"\n" -"Output options:\n" -" -q, --quiet Quiet execution\n" -" -v, --verbose Verbose execution\n" -" --debug Very verbose execution\n" -"\n" -"Help options:\n" -" -V, --version Display version\n" -" -l, --license Display licensing information\n" -" -h, --help Display this help\n" -"\n", basename(EXEC_NAME)); - ntfs_log_info("%s%s\n", ntfs_bugs, ntfs_home); -} - -/** - * mkntfs_version - */ -static void mkntfs_version(void) -{ - ntfs_log_info("\n%s v%s (libntfs %s)\n\n", EXEC_NAME, VERSION, - ntfs_libntfs_version()); - ntfs_log_info("Create an NTFS volume on a user specified (block) " - "device.\n\n"); - ntfs_log_info("Copyright (c) 2000-2007 Anton Altaparmakov\n"); - ntfs_log_info("Copyright (c) 2001-2005 Richard Russon\n"); - ntfs_log_info("Copyright (c) 2002-2006 Szabolcs Szakacsits\n"); - ntfs_log_info("Copyright (c) 2005 Erik Sornes\n"); - ntfs_log_info("Copyright (c) 2007 Yura Pakhuchiy\n"); - ntfs_log_info("\n%s\n%s%s\n", ntfs_gpl, ntfs_bugs, ntfs_home); -} - - -/** - * mkntfs_parse_long - */ -static BOOL mkntfs_parse_long(const char *string, const char *name, long *num) -{ - char *end = NULL; - long tmp; - - if (!string || !name || !num) - return FALSE; - - if (*num >= 0) { - ntfs_log_error("You may only specify the %s once.\n", name); - return FALSE; - } - - tmp = strtol(string, &end, 0); - if (end && *end) { - ntfs_log_error("Cannot understand the %s '%s'.\n", name, string); - return FALSE; - } else { - *num = tmp; - return TRUE; - } -} - -/** - * mkntfs_parse_llong - */ -static BOOL mkntfs_parse_llong(const char *string, const char *name, - long long *num) -{ - char *end = NULL; - long long tmp; - - if (!string || !name || !num) - return FALSE; - - if (*num >= 0) { - ntfs_log_error("You may only specify the %s once.\n", name); - return FALSE; - } - - tmp = strtoll(string, &end, 0); - if (end && *end) { - ntfs_log_error("Cannot understand the %s '%s'.\n", name, - string); - return FALSE; - } else { - *num = tmp; - return TRUE; - } -} - -/** - * mkntfs_init_options - */ -static void mkntfs_init_options(struct mkntfs_options *opts2) -{ - if (!opts2) - return; - - memset(opts2, 0, sizeof(*opts2)); - - /* Mark all the numeric options as "unset". */ - opts2->cluster_size = -1; - opts2->heads = -1; - opts2->mft_zone_multiplier = -1; - opts2->num_sectors = -1; - opts2->part_start_sect = -1; - opts2->sector_size = -1; - opts2->sectors_per_track = -1; -} - -/** - * mkntfs_parse_options - */ -static BOOL mkntfs_parse_options(int argc, char *argv[], struct mkntfs_options *opts2) -{ - static const char *sopt = "-c:CfFhH:IlL:np:qQs:S:TvVz:"; - static const struct option lopt[] = { - { "cluster-size", required_argument, NULL, 'c' }, - { "debug", no_argument, NULL, 'Z' }, - { "enable-compression", no_argument, NULL, 'C' }, - { "fast", no_argument, NULL, 'f' }, - { "force", no_argument, NULL, 'F' }, - { "heads", required_argument, NULL, 'H' }, - { "help", no_argument, NULL, 'h' }, - { "label", required_argument, NULL, 'L' }, - { "license", no_argument, NULL, 'l' }, - { "mft-zone-multiplier",required_argument, NULL, 'z' }, - { "no-action", no_argument, NULL, 'n' }, - { "no-indexing", no_argument, NULL, 'I' }, - { "partition-start", required_argument, NULL, 'p' }, - { "quick", no_argument, NULL, 'Q' }, - { "quiet", no_argument, NULL, 'q' }, - { "sector-size", required_argument, NULL, 's' }, - { "sectors-per-track", required_argument, NULL, 'S' }, - { "verbose", no_argument, NULL, 'v' }, - { "version", no_argument, NULL, 'V' }, - { "zero-time", no_argument, NULL, 'T' }, - { NULL, 0, NULL, 0 } - }; - - int c = -1; - int lic = 0; - int err = 0; - int ver = 0; - - if (!argv || !opts2) { - ntfs_log_error("Internal error: invalid parameters to " - "mkntfs_options.\n"); - return FALSE; - } - - opterr = 0; /* We'll handle the errors, thank you. */ - - while ((c = getopt_long(argc, argv, sopt, lopt, NULL)) != -1) { - switch (c) { - case 1: /* A device, or a number of sectors */ - if (!opts2->dev_name) - opts2->dev_name = argv[optind - 1]; - else if (!mkntfs_parse_llong(optarg, - "number of sectors", - &opts2->num_sectors)) - err++; - break; - case 'C': - opts2->enable_compression = TRUE; - break; - case 'c': - if (!mkntfs_parse_long(optarg, "cluster size", - &opts2->cluster_size)) - err++; - break; - case 'F': - opts2->force = TRUE; - break; - case 'f': /* fast */ - case 'Q': /* quick */ - opts2->quick_format = TRUE; - break; - case 'H': - if (!mkntfs_parse_long(optarg, "heads", &opts2->heads)) - err++; - break; - case 'h': - err++; /* display help */ - break; - case 'I': - opts2->disable_indexing = TRUE; - break; - case 'L': - if (!opts2->label) { - opts2->label = argv[optind-1]; - } else { - ntfs_log_error("You may only specify the label " - "once.\n"); - err++; - } - break; - case 'l': - lic++; /* display the license */ - break; - case 'n': - opts2->no_action = TRUE; - break; - case 'p': - if (!mkntfs_parse_llong(optarg, "partition start", - &opts2->part_start_sect)) - err++; - break; - case 'q': - ntfs_log_clear_levels(NTFS_LOG_LEVEL_QUIET | - NTFS_LOG_LEVEL_VERBOSE | - NTFS_LOG_LEVEL_PROGRESS); - break; - case 's': - if (!mkntfs_parse_long(optarg, "sector size", - &opts2->sector_size)) - err++; - break; - case 'S': - if (!mkntfs_parse_long(optarg, "sectors per track", - &opts2->sectors_per_track)) - err++; - break; - case 'T': - opts2->use_epoch_time = TRUE; - break; - case 'v': - ntfs_log_set_levels(NTFS_LOG_LEVEL_QUIET | - NTFS_LOG_LEVEL_VERBOSE | - NTFS_LOG_LEVEL_PROGRESS); - break; - case 'V': - ver++; /* display version info */ - break; - case 'Z': /* debug - turn on everything */ - ntfs_log_set_levels(NTFS_LOG_LEVEL_DEBUG | - NTFS_LOG_LEVEL_TRACE | - NTFS_LOG_LEVEL_VERBOSE | - NTFS_LOG_LEVEL_QUIET); - break; - case 'z': - if (!mkntfs_parse_long(optarg, "mft zone multiplier", - &opts2->mft_zone_multiplier)) - err++; - break; - default: - if (ntfs_log_parse_option (argv[optind-1])) - break; - if (((optopt == 'c') || (optopt == 'H') || - (optopt == 'L') || (optopt == 'p') || - (optopt == 's') || (optopt == 'S') || - (optopt == 'N') || (optopt == 'z')) && - (!optarg)) { - ntfs_log_error("Option '%s' requires an " - "argument.\n", argv[optind-1]); - } else if (optopt != '?') { - ntfs_log_error("Unknown option '%s'.\n", - argv[optind - 1]); - } - err++; - break; - } - } - - if (!err && !ver && !lic) { - if (opts2->dev_name == NULL) { - if (argc > 1) - ntfs_log_error("You must specify a device.\n"); - err++; - } - } - - if (ver) - mkntfs_version(); - if (lic) - mkntfs_license(); - if (err) - mkntfs_usage(); - - return (!err && !ver && !lic); -} - - -/** - * mkntfs_time - */ -static time_t mkntfs_time(void) -{ - if (!opts.use_epoch_time) - return time(NULL); - return 0; -} - -/** - * append_to_bad_blocks - */ -static BOOL append_to_bad_blocks(unsigned long long block) -{ - long long *new_buf; - - if (!(g_num_bad_blocks & 15)) { - new_buf = realloc(g_bad_blocks, (g_num_bad_blocks + 16) * - sizeof(long long)); - if (!new_buf) { - ntfs_log_perror("Reallocating memory for bad blocks " - "list failed"); - return FALSE; - } - g_bad_blocks = new_buf; - } - g_bad_blocks[g_num_bad_blocks++] = block; - return TRUE; -} - -/** - * mkntfs_write - */ -static long long mkntfs_write(struct ntfs_device *dev, - const void *b, long long count) -{ - long long bytes_written, total; - int retry; - - if (opts.no_action) - return count; - total = 0LL; - retry = 0; - do { - bytes_written = dev->d_ops->write(dev, b, count); - if (bytes_written == -1LL) { - retry = errno; - ntfs_log_perror("Error writing to %s", dev->d_name); - errno = retry; - return bytes_written; - } else if (!bytes_written) { - retry++; - } else { - count -= bytes_written; - total += bytes_written; - } - } while (count && retry < 3); - if (count) - ntfs_log_error("Failed to complete writing to %s after three retries." - "\n", dev->d_name); - return total; -} - -/** - * ntfs_rlwrite - Write data to disk on clusters found in a runlist. - * - * Write to disk the clusters contained in the runlist @rl taking the data - * from @val. Take @val_len bytes from @val and pad the rest with zeroes. - * - * If the @rl specifies a completely sparse file, @val is allowed to be NULL. - * - * @inited_size if not NULL points to an output variable which will contain - * the actual number of bytes written to disk. I.e. this will not include - * sparse bytes for example. - * - * Return the number of bytes written (minus padding) or -1 on error. Errno - * will be set to the error code. - */ -static s64 ntfs_rlwrite(struct ntfs_device *dev, const runlist *rl, - const u8 *val, const s64 val_len, s64 *inited_size) -{ - s64 bytes_written, total, length, delta; - int retry, i; - - if (inited_size) - *inited_size = 0LL; - if (opts.no_action) - return val_len; - total = 0LL; - delta = 0LL; - for (i = 0; rl[i].length; i++) { - length = rl[i].length * g_vol->cluster_size; - /* Don't write sparse runs. */ - if (rl[i].lcn == -1) { - total += length; - if (!val) - continue; - /* TODO: Check that *val is really zero at pos and len. */ - continue; - } - /* - * Break up the write into the real data write and then a write - * of zeroes between the end of the real data and the end of - * the (last) run. - */ - if (total + length > val_len) { - delta = length; - length = val_len - total; - delta -= length; - } - if (dev->d_ops->seek(dev, rl[i].lcn * g_vol->cluster_size, - SEEK_SET) == (off_t)-1) - return -1LL; - retry = 0; - do { - bytes_written = dev->d_ops->write(dev, val + total, - length); - if (bytes_written == -1LL) { - retry = errno; - ntfs_log_perror("Error writing to %s", - dev->d_name); - errno = retry; - return bytes_written; - } - if (bytes_written) { - length -= bytes_written; - total += bytes_written; - if (inited_size) - *inited_size += bytes_written; - } else { - retry++; - } - } while (length && retry < 3); - if (length) { - ntfs_log_error("Failed to complete writing to %s after three " - "retries.\n", dev->d_name); - return total; - } - } - if (delta) { - int eo; - char *b = ntfs_calloc(delta); - if (!b) - return -1; - bytes_written = mkntfs_write(dev, b, delta); - eo = errno; - free(b); - errno = eo; - if (bytes_written == -1LL) - return bytes_written; - } - return total; -} - -/** - * make_room_for_attribute - 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 -errno on error. Possible error codes are: - * - * -ENOSPC There is not enough space available to complete - * operation. The caller has to make space before calling - * this. - * -EINVAL Can only occur if mkntfs was compiled with -DDEBUG. Means - * the input parameters were faulty. - */ -static int make_room_for_attribute(MFT_RECORD *m, char *pos, const u32 size) -{ - u32 biu; - - if (!size) - return 0; -#ifdef DEBUG - /* - * Rigorous consistency checks. Always return -EINVAL even if more - * appropriate codes exist for simplicity of parsing the return value. - */ - if (size != ((size + 7) & ~7)) { - ntfs_log_error("make_room_for_attribute() received non 8-byte aligned " - "size.\n"); - return -EINVAL; - } - if (!m || !pos) - return -EINVAL; - if (pos < (char*)m || pos + size < (char*)m || - pos > (char*)m + le32_to_cpu(m->bytes_allocated) || - pos + size > (char*)m + le32_to_cpu(m->bytes_allocated)) - return -EINVAL; - /* The -8 is for the attribute terminator. */ - if (pos - (char*)m > (int)le32_to_cpu(m->bytes_in_use) - 8) - return -EINVAL; -#endif - biu = le32_to_cpu(m->bytes_in_use); - /* Do we have enough space? */ - if (biu + size > le32_to_cpu(m->bytes_allocated)) - return -ENOSPC; - /* Move everything after pos to pos + size. */ - memmove(pos + size, pos, biu - (pos - (char*)m)); - /* Update mft record. */ - m->bytes_in_use = cpu_to_le32(biu + size); - return 0; -} - -/** - * deallocate_scattered_clusters - */ -static void deallocate_scattered_clusters(const runlist *rl) -{ - LCN j; - int i; - - if (!rl) - return; - /* Iterate over all runs in the runlist @rl. */ - for (i = 0; rl[i].length; i++) { - /* Skip sparse runs. */ - if (rl[i].lcn == -1LL) - continue; - /* Deallocate the current run. */ - for (j = rl[i].lcn; j < rl[i].lcn + rl[i].length; j++) - ntfs_bit_set(g_lcn_bitmap, j, 0); - } -} - -/** - * allocate_scattered_clusters - * @clusters: Amount of clusters to allocate. - * - * Allocate @clusters and create a runlist of the allocated clusters. - * - * Return the allocated runlist. Caller has to free the runlist when finished - * with it. - * - * On error return NULL and errno is set to the error code. - * - * TODO: We should be returning the size as well, but for mkntfs this is not - * necessary. - */ -static runlist * allocate_scattered_clusters(s64 clusters) -{ - runlist *rl = NULL, *rlt; - VCN vcn = 0LL; - LCN lcn, end, prev_lcn = 0LL; - int rlpos = 0; - int rlsize = 0; - s64 prev_run_len = 0LL; - char bit; - - end = g_vol->nr_clusters; - /* Loop until all clusters are allocated. */ - while (clusters) { - /* Loop in current zone until we run out of free clusters. */ - for (lcn = g_mft_zone_end; lcn < end; lcn++) { - bit = ntfs_bit_get_and_set(g_lcn_bitmap, lcn, 1); - if (bit) - continue; - /* - * Reallocate memory if necessary. Make sure we have - * enough for the terminator entry as well. - */ - if ((rlpos + 2) * (int)sizeof(runlist) >= rlsize) { - rlsize += 4096; /* PAGE_SIZE */ - rlt = realloc(rl, rlsize); - if (!rlt) - goto err_end; - rl = rlt; - } - /* Coalesce with previous run if adjacent LCNs. */ - if (prev_lcn == lcn - prev_run_len) { - rl[rlpos - 1].length = ++prev_run_len; - vcn++; - } else { - rl[rlpos].vcn = vcn++; - rl[rlpos].lcn = lcn; - prev_lcn = lcn; - rl[rlpos].length = 1LL; - prev_run_len = 1LL; - rlpos++; - } - /* Done? */ - if (!--clusters) { - /* Add terminator element and return. */ - rl[rlpos].vcn = vcn; - rl[rlpos].lcn = 0LL; - rl[rlpos].length = 0LL; - return rl; - } - - } - /* Switch to next zone, decreasing mft zone by factor 2. */ - end = g_mft_zone_end; - g_mft_zone_end >>= 1; - /* Have we run out of space on the volume? */ - if (g_mft_zone_end <= 0) - goto err_end; - } - return rl; -err_end: - if (rl) { - /* Add terminator element. */ - rl[rlpos].vcn = vcn; - rl[rlpos].lcn = -1LL; - rl[rlpos].length = 0LL; - /* Deallocate all allocated clusters. */ - deallocate_scattered_clusters(rl); - /* Free the runlist. */ - free(rl); - } - return NULL; -} - -/** - * 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 mkntfs_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; - ntfschar *upcase = g_vol->upcase; - u32 upcase_len = g_vol->upcase_len; - - /* - * 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 if (name && !ntfs_names_are_equal(name, name_len, - (ntfschar*)((char*)a + le16_to_cpu(a->name_offset)), - a->name_length, ic, upcase, upcase_len)) { - int rc; - - rc = ntfs_names_collate(name, name_len, - (ntfschar*)((char*)a + - le16_to_cpu(a->name_offset)), - a->name_length, 1, IGNORE_CASE, - upcase, upcase_len); - /* - * If @name collates before a->name, there is no - * matching attribute. - */ - if (rc == -1) { - errno = ENOENT; - return -1; - } - /* If the strings are not equal, continue search. */ - if (rc) - continue; - rc = ntfs_names_collate(name, name_len, - (ntfschar*)((char*)a + - le16_to_cpu(a->name_offset)), - a->name_length, 1, CASE_SENSITIVE, - upcase, upcase_len); - if (rc == -1) { - errno = ENOENT; - return -1; - } - if (rc) - 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 { - int rc; - - rc = memcmp(val, (char*)a +le16_to_cpu(a->u.res.value_offset), - min(val_len, - le32_to_cpu(a->u.res.value_length))); - /* - * If @val collates before the current attribute's - * value, there is no matching attribute. - */ - if (!rc) { - u32 avl; - avl = le32_to_cpu(a->u.res.value_length); - if (val_len == avl) - return 0; - if (val_len < avl) { - errno = ENOENT; - return -1; - } - } else if (rc < 0) { - errno = ENOENT; - return -1; - } - } - } - ntfs_log_trace("File is corrupt. Run chkdsk.\n"); - errno = EIO; - return -1; -} - -/** - * 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. - */ -static int mkntfs_attr_lookup(const ATTR_TYPES type, const ntfschar *name, - const u32 name_len, const IGNORE_CASE_BOOL ic, - const VCN lowest_vcn __attribute__((unused)), const u8 *val, - const u32 val_len, ntfs_attr_search_ctx *ctx) -{ - ntfs_inode *base_ni; - - if (!ctx || !ctx->mrec || !ctx->attr) { - errno = EINVAL; - return -1; - } - 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) - return mkntfs_attr_find(type, name, name_len, ic, val, val_len, - ctx); - errno = EOPNOTSUPP; - return -1; -} - -/** - * insert_positioned_attr_in_mft_record - * - * Create a non-resident attribute with a predefined on disk location - * specified by the runlist @rl. The clusters specified by @rl are assumed to - * be allocated already. - * - * Return 0 on success and -errno on error. - */ -static int insert_positioned_attr_in_mft_record(MFT_RECORD *m, - const ATTR_TYPES type, const char *name, u32 name_len, - const IGNORE_CASE_BOOL ic, const ATTR_FLAGS flags, - const runlist *rl, const u8 *val, const s64 val_len) -{ - ntfs_attr_search_ctx *ctx; - ATTR_RECORD *a; - u16 hdr_size; - int asize, mpa_size, err, i; - s64 bw = 0, inited_size; - VCN highest_vcn; - ntfschar *uname = NULL; - int uname_len = 0; - /* - if (base record) - attr_lookup(); - else - */ - - uname = ntfs_str2ucs(name, &uname_len); - if (!uname) - return -errno; - - /* Check if the attribute is already there. */ - ctx = ntfs_attr_get_search_ctx(NULL, m); - if (!ctx) { - ntfs_log_error("Failed to allocate attribute search context.\n"); - err = -ENOMEM; - goto err_out; - } - if (ic == IGNORE_CASE) { - ntfs_log_error("FIXME: Hit unimplemented code path #1.\n"); - err = -EOPNOTSUPP; - goto err_out; - } - if (!mkntfs_attr_lookup(type, uname, uname_len, ic, 0, NULL, 0, ctx)) { - err = -EEXIST; - goto err_out; - } - if (errno != ENOENT) { - ntfs_log_error("Corrupt inode.\n"); - err = -errno; - goto err_out; - } - a = ctx->attr; - if (flags & ATTR_COMPRESSION_MASK) { - ntfs_log_error("Compressed attributes not supported yet.\n"); - /* FIXME: Compress attribute into a temporary buffer, set */ - /* val accordingly and save the compressed size. */ - err = -EOPNOTSUPP; - goto err_out; - } - if (flags & (ATTR_IS_ENCRYPTED | ATTR_IS_SPARSE)) { - ntfs_log_error("Encrypted/sparse attributes not supported.\n"); - err = -EOPNOTSUPP; - goto err_out; - } - if (flags & ATTR_COMPRESSION_MASK) { - hdr_size = 72; - /* FIXME: This compression stuff is all wrong. Never mind for */ - /* now. (AIA) */ - if (val_len) - mpa_size = 0; /* get_size_for_compressed_mapping_pairs(rl); */ - else - mpa_size = 0; - } else { - hdr_size = 64; - if (val_len) { - mpa_size = ntfs_get_size_for_mapping_pairs(g_vol, rl, 0); - if (mpa_size < 0) { - err = -errno; - ntfs_log_error("Failed to get size for mapping " - "pairs.\n"); - goto err_out; - } - } else { - mpa_size = 0; - } - } - /* Mapping pairs array and next attribute must be 8-byte aligned. */ - asize = (((int)hdr_size + ((name_len + 7) & ~7) + mpa_size) + 7) & ~7; - /* Get the highest vcn. */ - for (i = 0, highest_vcn = 0LL; rl[i].length; i++) - highest_vcn += rl[i].length; - /* Does the value fit inside the allocated size? */ - if (highest_vcn * g_vol->cluster_size < val_len) { - ntfs_log_error("BUG: Allocated size is smaller than data size!\n"); - err = -EINVAL; - goto err_out; - } - err = make_room_for_attribute(m, (char*)a, asize); - if (err == -ENOSPC) { - /* - * FIXME: Make space! (AIA) - * can we make it non-resident? if yes, do that. - * does it fit now? yes -> do it. - * m's $DATA or $BITMAP+$INDEX_ALLOCATION resident? - * yes -> make non-resident - * does it fit now? yes -> do it. - * make all attributes non-resident - * does it fit now? yes -> do it. - * m is a base record? yes -> allocate extension record - * does the new attribute fit in there? yes -> do it. - * split up runlist into extents and place each in an extension - * record. - * FIXME: the check for needing extension records should be - * earlier on as it is very quick: asize > m->bytes_allocated? - */ - err = -EOPNOTSUPP; - goto err_out; -#ifdef DEBUG - } else if (err == -EINVAL) { - ntfs_log_error("BUG(): in insert_positioned_attribute_in_mft_" - "record(): make_room_for_attribute() returned " - "error: EINVAL!\n"); - goto err_out; -#endif - } - a->type = type; - a->length = cpu_to_le32(asize); - a->non_resident = 1; - a->name_length = name_len; - a->name_offset = cpu_to_le16(hdr_size); - a->flags = flags; - a->instance = m->next_attr_instance; - m->next_attr_instance = cpu_to_le16((le16_to_cpu(m->next_attr_instance) - + 1) & 0xffff); - a->u.nonres.lowest_vcn = 0; - a->u.nonres.highest_vcn = cpu_to_sle64(highest_vcn - 1LL); - a->u.nonres.mapping_pairs_offset = cpu_to_le16(hdr_size + ((name_len + 7) & ~7)); - memset(a->u.nonres.reserved1, 0, sizeof(a->u.nonres.reserved1)); - /* FIXME: Allocated size depends on compression. */ - a->u.nonres.allocated_size = cpu_to_sle64(highest_vcn * g_vol->cluster_size); - a->u.nonres.data_size = cpu_to_sle64(val_len); - if (name_len) - memcpy((char*)a + hdr_size, uname, name_len << 1); - if (flags & ATTR_COMPRESSION_MASK) { - if (flags & ATTR_COMPRESSION_MASK & ~ATTR_IS_COMPRESSED) { - ntfs_log_error("Unknown compression format. Reverting " - "to standard compression.\n"); - a->flags &= ~ATTR_COMPRESSION_MASK; - a->flags |= ATTR_IS_COMPRESSED; - } - a->u.nonres.compression_unit = 4; - inited_size = val_len; - /* FIXME: Set the compressed size. */ - a->u.nonres.compressed_size = 0; - /* FIXME: Write out the compressed data. */ - /* FIXME: err = build_mapping_pairs_compressed(); */ - err = -EOPNOTSUPP; - } else { - a->u.nonres.compression_unit = 0; - bw = ntfs_rlwrite(g_vol->u.dev, rl, val, val_len, &inited_size); - if (bw != val_len) { - ntfs_log_error("Error writing non-resident attribute " - "value.\n"); - return -errno; - } - err = ntfs_mapping_pairs_build(g_vol, (u8*)a + hdr_size + - ((name_len + 7) & ~7), mpa_size, rl, 0, NULL); - } - a->u.nonres.initialized_size = cpu_to_sle64(inited_size); - if (err < 0 || bw != val_len) { - /* FIXME: Handle error. */ - /* deallocate clusters */ - /* remove attribute */ - if (err >= 0) - err = -EIO; - ntfs_log_error("insert_positioned_attr_in_mft_record failed " - "with error %i.\n", err < 0 ? err : (int)bw); - } -err_out: - if (ctx) - ntfs_attr_put_search_ctx(ctx); - ntfs_ucsfree(uname); - return err; -} - -/** - * insert_non_resident_attr_in_mft_record - * - * Return 0 on success and -errno on error. - */ -static int insert_non_resident_attr_in_mft_record(MFT_RECORD *m, - const ATTR_TYPES type, const char *name, u32 name_len, - const IGNORE_CASE_BOOL ic, const ATTR_FLAGS flags, - const u8 *val, const s64 val_len) -{ - ntfs_attr_search_ctx *ctx; - ATTR_RECORD *a; - u16 hdr_size; - int asize, mpa_size, err, i; - runlist *rl = NULL; - s64 bw = 0; - ntfschar *uname = NULL; - int uname_len = 0; - /* - if (base record) - attr_lookup(); - else - */ - - uname = ntfs_str2ucs(name, &uname_len); - if (!uname) - return -errno; - - /* Check if the attribute is already there. */ - ctx = ntfs_attr_get_search_ctx(NULL, m); - if (!ctx) { - ntfs_log_error("Failed to allocate attribute search context.\n"); - err = -ENOMEM; - goto err_out; - } - if (ic == IGNORE_CASE) { - ntfs_log_error("FIXME: Hit unimplemented code path #2.\n"); - err = -EOPNOTSUPP; - goto err_out; - } - if (!mkntfs_attr_lookup(type, uname, uname_len, ic, 0, NULL, 0, ctx)) { - err = -EEXIST; - goto err_out; - } - if (errno != ENOENT) { - ntfs_log_error("Corrupt inode.\n"); - err = -errno; - goto err_out; - } - a = ctx->attr; - if (flags & ATTR_COMPRESSION_MASK) { - ntfs_log_error("Compressed attributes not supported yet.\n"); - /* FIXME: Compress attribute into a temporary buffer, set */ - /* val accordingly and save the compressed size. */ - err = -EOPNOTSUPP; - goto err_out; - } - if (flags & (ATTR_IS_ENCRYPTED | ATTR_IS_SPARSE)) { - ntfs_log_error("Encrypted/sparse attributes not supported.\n"); - err = -EOPNOTSUPP; - goto err_out; - } - if (val_len) { - rl = allocate_scattered_clusters((val_len + - g_vol->cluster_size - 1) / g_vol->cluster_size); - if (!rl) { - err = -errno; - ntfs_log_perror("Failed to allocate scattered clusters"); - goto err_out; - } - } else { - rl = NULL; - } - if (flags & ATTR_COMPRESSION_MASK) { - hdr_size = 72; - /* FIXME: This compression stuff is all wrong. Never mind for */ - /* now. (AIA) */ - if (val_len) - mpa_size = 0; /* get_size_for_compressed_mapping_pairs(rl); */ - else - mpa_size = 0; - } else { - hdr_size = 64; - if (val_len) { - mpa_size = ntfs_get_size_for_mapping_pairs(g_vol, rl, 0); - if (mpa_size < 0) { - err = -errno; - ntfs_log_error("Failed to get size for mapping " - "pairs.\n"); - goto err_out; - } - } else { - mpa_size = 0; - } - } - /* Mapping pairs array and next attribute must be 8-byte aligned. */ - asize = (((int)hdr_size + ((name_len + 7) & ~7) + mpa_size) + 7) & ~7; - err = make_room_for_attribute(m, (char*)a, asize); - if (err == -ENOSPC) { - /* - * FIXME: Make space! (AIA) - * can we make it non-resident? if yes, do that. - * does it fit now? yes -> do it. - * m's $DATA or $BITMAP+$INDEX_ALLOCATION resident? - * yes -> make non-resident - * does it fit now? yes -> do it. - * make all attributes non-resident - * does it fit now? yes -> do it. - * m is a base record? yes -> allocate extension record - * does the new attribute fit in there? yes -> do it. - * split up runlist into extents and place each in an extension - * record. - * FIXME: the check for needing extension records should be - * earlier on as it is very quick: asize > m->bytes_allocated? - */ - err = -EOPNOTSUPP; - goto err_out; -#ifdef DEBUG - } else if (err == -EINVAL) { - ntfs_log_error("BUG(): in insert_non_resident_attribute_in_" - "mft_record(): make_room_for_attribute() " - "returned error: EINVAL!\n"); - goto err_out; -#endif - } - a->type = type; - a->length = cpu_to_le32(asize); - a->non_resident = 1; - a->name_length = name_len; - a->name_offset = cpu_to_le16(hdr_size); - a->flags = flags; - a->instance = m->next_attr_instance; - m->next_attr_instance = cpu_to_le16((le16_to_cpu(m->next_attr_instance) - + 1) & 0xffff); - a->u.nonres.lowest_vcn = 0; - for (i = 0; rl[i].length; i++) - ; - a->u.nonres.highest_vcn = cpu_to_sle64(rl[i].vcn - 1); - a->u.nonres.mapping_pairs_offset = cpu_to_le16(hdr_size + ((name_len + 7) & ~7)); - memset(a->u.nonres.reserved1, 0, sizeof(a->u.nonres.reserved1)); - /* FIXME: Allocated size depends on compression. */ - a->u.nonres.allocated_size = cpu_to_sle64((val_len + (g_vol->cluster_size - 1)) & - ~(g_vol->cluster_size - 1)); - a->u.nonres.data_size = cpu_to_sle64(val_len); - a->u.nonres.initialized_size = cpu_to_sle64(val_len); - if (name_len) - memcpy((char*)a + hdr_size, uname, name_len << 1); - if (flags & ATTR_COMPRESSION_MASK) { - if (flags & ATTR_COMPRESSION_MASK & ~ATTR_IS_COMPRESSED) { - ntfs_log_error("Unknown compression format. Reverting " - "to standard compression.\n"); - a->flags &= ~ATTR_COMPRESSION_MASK; - a->flags |= ATTR_IS_COMPRESSED; - } - a->u.nonres.compression_unit = 4; - /* FIXME: Set the compressed size. */ - a->u.nonres.compressed_size = 0; - /* FIXME: Write out the compressed data. */ - /* FIXME: err = build_mapping_pairs_compressed(); */ - err = -EOPNOTSUPP; - } else { - a->u.nonres.compression_unit = 0; - bw = ntfs_rlwrite(g_vol->u.dev, rl, val, val_len, NULL); - if (bw != val_len) { - ntfs_log_error("Error writing non-resident attribute " - "value.\n"); - return -errno; - } - err = ntfs_mapping_pairs_build(g_vol, (u8*)a + hdr_size + - ((name_len + 7) & ~7), mpa_size, rl, 0, NULL); - } - if (err < 0 || bw != val_len) { - /* FIXME: Handle error. */ - /* deallocate clusters */ - /* remove attribute */ - if (err >= 0) - err = -EIO; - ntfs_log_error("insert_non_resident_attr_in_mft_record failed with " - "error %lld.\n", (long long) (err < 0 ? err : bw)); - } -err_out: - if (ctx) - ntfs_attr_put_search_ctx(ctx); - ntfs_ucsfree(uname); - free(rl); - return err; -} - -/** - * insert_resident_attr_in_mft_record - * - * Return 0 on success and -errno on error. - */ -static int insert_resident_attr_in_mft_record(MFT_RECORD *m, - const ATTR_TYPES type, const char *name, u32 name_len, - const IGNORE_CASE_BOOL ic, const ATTR_FLAGS flags, - const RESIDENT_ATTR_FLAGS res_flags, - const u8 *val, const u32 val_len) -{ - ntfs_attr_search_ctx *ctx; - ATTR_RECORD *a; - int asize, err; - ntfschar *uname = NULL; - int uname_len = 0; - /* - if (base record) - mkntfs_attr_lookup(); - else - */ - - uname = ntfs_str2ucs(name, &uname_len); - if (!uname) - return -errno; - - /* Check if the attribute is already there. */ - ctx = ntfs_attr_get_search_ctx(NULL, m); - if (!ctx) { - ntfs_log_error("Failed to allocate attribute search context.\n"); - err = -ENOMEM; - goto err_out; - } - if (ic == IGNORE_CASE) { - ntfs_log_error("FIXME: Hit unimplemented code path #3.\n"); - err = -EOPNOTSUPP; - goto err_out; - } - if (!mkntfs_attr_lookup(type, uname, uname_len, ic, 0, val, val_len, - ctx)) { - err = -EEXIST; - goto err_out; - } - if (errno != ENOENT) { - ntfs_log_error("Corrupt inode.\n"); - err = -errno; - goto err_out; - } - a = ctx->attr; - /* sizeof(resident attribute record header) == 24 */ - asize = ((24 + ((name_len + 7) & ~7) + val_len) + 7) & ~7; - err = make_room_for_attribute(m, (char*)a, asize); - if (err == -ENOSPC) { - /* - * FIXME: Make space! (AIA) - * can we make it non-resident? if yes, do that. - * does it fit now? yes -> do it. - * m's $DATA or $BITMAP+$INDEX_ALLOCATION resident? - * yes -> make non-resident - * does it fit now? yes -> do it. - * make all attributes non-resident - * does it fit now? yes -> do it. - * m is a base record? yes -> allocate extension record - * does the new attribute fit in there? yes -> do it. - * split up runlist into extents and place each in an extension - * record. - * FIXME: the check for needing extension records should be - * earlier on as it is very quick: asize > m->bytes_allocated? - */ - err = -EOPNOTSUPP; - goto err_out; - } -#ifdef DEBUG - if (err == -EINVAL) { - ntfs_log_error("BUG(): in insert_resident_attribute_in_mft_" - "record(): make_room_for_attribute() returned " - "error: EINVAL!\n"); - goto err_out; - } -#endif - a->type = type; - a->length = cpu_to_le32(asize); - a->non_resident = 0; - a->name_length = name_len; - if (type == AT_OBJECT_ID) - a->name_offset = const_cpu_to_le16(0); - else - a->name_offset = const_cpu_to_le16(24); - a->flags = flags; - a->instance = m->next_attr_instance; - m->next_attr_instance = cpu_to_le16((le16_to_cpu(m->next_attr_instance) - + 1) & 0xffff); - a->u.res.value_length = cpu_to_le32(val_len); - a->u.res.value_offset = cpu_to_le16(24 + ((name_len + 7) & ~7)); - a->u.res.resident_flags = res_flags; - a->u.res.reservedR = 0; - if (name_len) - memcpy((char*)a + 24, uname, name_len << 1); - if (val_len) - memcpy((char*)a + le16_to_cpu(a->u.res.value_offset), val, val_len); -err_out: - if (ctx) - ntfs_attr_put_search_ctx(ctx); - ntfs_ucsfree(uname); - return err; -} - - -/** - * add_attr_std_info - * - * Return 0 on success or -errno on error. - */ -static int add_attr_std_info(MFT_RECORD *m, const FILE_ATTR_FLAGS flags, - le32 security_id) -{ - STANDARD_INFORMATION si; - int err, sd_size; - - sd_size = 48; - - si.creation_time = utc2ntfs(mkntfs_time()); - si.last_data_change_time = si.creation_time; - si.last_mft_change_time = si.creation_time; - si.last_access_time = si.creation_time; - si.file_attributes = flags; /* already LE */ - si.u.v30.maximum_versions = cpu_to_le32(0); - si.u.v30.version_number = cpu_to_le32(0); - si.u.v30.class_id = cpu_to_le32(0); - si.u.v30.security_id = security_id; - if (si.u.v30.security_id != 0) - sd_size = 72; - /* FIXME: $Quota support... */ - si.u.v30.owner_id = cpu_to_le32(0); - si.u.v30.quota_charged = cpu_to_le64(0ULL); - /* FIXME: $UsnJrnl support... Not needed on fresh w2k3-volume */ - si.u.v30.usn = cpu_to_le64(0ULL); - /* NTFS 1.2: size of si = 48, NTFS 3.[01]: size of si = 72 */ - err = insert_resident_attr_in_mft_record(m, AT_STANDARD_INFORMATION, - NULL, 0, 0, 0, 0, (u8*)&si, sd_size); - if (err < 0) - ntfs_log_perror("add_attr_std_info failed"); - return err; -} - -/** - * add_attr_file_name - * - * Return 0 on success or -errno on error. - */ -static int add_attr_file_name(MFT_RECORD *m, const leMFT_REF parent_dir, - const s64 allocated_size, const s64 data_size, - const FILE_ATTR_FLAGS flags, const u16 packed_ea_size, - const u32 reparse_point_tag, const char *file_name, - const FILE_NAME_TYPE_FLAGS file_name_type) -{ - ntfs_attr_search_ctx *ctx; - STANDARD_INFORMATION *si; - FILE_NAME_ATTR *fn; - int i, fn_size; - ntfschar *uname; - - /* Check if the attribute is already there. */ - ctx = ntfs_attr_get_search_ctx(NULL, m); - if (!ctx) { - ntfs_log_error("Failed to get attribute search context.\n"); - return -ENOMEM; - } - if (mkntfs_attr_lookup(AT_STANDARD_INFORMATION, AT_UNNAMED, 0, 0, 0, - NULL, 0, ctx)) { - int eo = errno; - ntfs_log_error("BUG: Standard information attribute not " - "present in file record.\n"); - ntfs_attr_put_search_ctx(ctx); - return -eo; - } - si = (STANDARD_INFORMATION*)((char*)ctx->attr + - le16_to_cpu(ctx->attr->u.res.value_offset)); - i = (strlen(file_name) + 1) * sizeof(ntfschar); - fn_size = sizeof(FILE_NAME_ATTR) + i; - fn = ntfs_malloc(fn_size); - if (!fn) { - ntfs_attr_put_search_ctx(ctx); - return -errno; - } - fn->parent_directory = parent_dir; - - fn->creation_time = si->creation_time; - fn->last_data_change_time = si->last_data_change_time; - fn->last_mft_change_time = si->last_mft_change_time; - fn->last_access_time = si->last_access_time; - ntfs_attr_put_search_ctx(ctx); - - fn->allocated_size = cpu_to_sle64(allocated_size); - fn->data_size = cpu_to_sle64(data_size); - fn->file_attributes = flags; - /* These are in a union so can't have both. */ - if (packed_ea_size && reparse_point_tag) { - free(fn); - return -EINVAL; - } - if (packed_ea_size) { - fn->u.s.packed_ea_size = cpu_to_le16(packed_ea_size); - fn->u.s.reserved = cpu_to_le16(0); - } else { - fn->u.reparse_point_tag = cpu_to_le32(reparse_point_tag); - } - fn->file_name_type = file_name_type; - uname = fn->file_name; - i = ntfs_mbstoucs(file_name, &uname, i); - if (i < 1) { - free(fn); - return -EINVAL; - } - if (i > 0xff) { - free(fn); - return -ENAMETOOLONG; - } - /* No terminating null in file names. */ - fn->file_name_length = i; - fn_size = sizeof(FILE_NAME_ATTR) + i * sizeof(ntfschar); - i = insert_resident_attr_in_mft_record(m, AT_FILE_NAME, NULL, 0, 0, - 0, RESIDENT_ATTR_IS_INDEXED, (u8*)fn, fn_size); - free(fn); - if (i < 0) - ntfs_log_error("add_attr_file_name failed: %s\n", strerror(-i)); - return i; -} - -#ifdef ENABLE_UUID - -/** - * add_attr_object_id - - * - * Note we insert only a basic object id which only has the GUID and none of - * the extended fields. This is because we currently only use this function - * when creating the object id for the volume. - * - * Return 0 on success or -errno on error. - */ -static int add_attr_object_id(MFT_RECORD *m, const GUID *object_id) -{ - OBJECT_ID_ATTR oi; - int err; - - oi = (OBJECT_ID_ATTR) { - .object_id = *object_id, - }; - err = insert_resident_attr_in_mft_record(m, AT_OBJECT_ID, NULL, - 0, 0, 0, 0, (u8*)&oi, sizeof(oi.object_id)); - if (err < 0) - ntfs_log_error("add_attr_vol_info failed: %s\n", strerror(-err)); - return err; -} - -#endif - -/** - * add_attr_sd - * - * Create the security descriptor attribute adding the security descriptor @sd - * of length @sd_len to the mft record @m. - * - * Return 0 on success or -errno on error. - */ -static int add_attr_sd(MFT_RECORD *m, const u8 *sd, const s64 sd_len) -{ - int err; - - /* Does it fit? NO: create non-resident. YES: create resident. */ - if (le32_to_cpu(m->bytes_in_use) + 24 + sd_len > - le32_to_cpu(m->bytes_allocated)) - err = insert_non_resident_attr_in_mft_record(m, - AT_SECURITY_DESCRIPTOR, NULL, 0, 0, 0, sd, - sd_len); - else - err = insert_resident_attr_in_mft_record(m, - AT_SECURITY_DESCRIPTOR, NULL, 0, 0, 0, 0, sd, - sd_len); - if (err < 0) - ntfs_log_error("add_attr_sd failed: %s\n", strerror(-err)); - return err; -} - -/** - * add_attr_data - * - * Return 0 on success or -errno on error. - */ -static int add_attr_data(MFT_RECORD *m, const char *name, const u32 name_len, - const IGNORE_CASE_BOOL ic, const ATTR_FLAGS flags, - const u8 *val, const s64 val_len) -{ - int err; - - /* - * Does it fit? NO: create non-resident. YES: create resident. - * - * FIXME: Introduced arbitrary limit of mft record allocated size - 512. - * This is to get around the problem that if $Bitmap/$DATA becomes too - * big, but is just small enough to be resident, we would make it - * resident, and later run out of space when creating the other - * attributes and this would cause us to abort as making resident - * attributes non-resident is not supported yet. - * The proper fix is to support making resident attribute non-resident. - */ - if (le32_to_cpu(m->bytes_in_use) + 24 + val_len > - min(le32_to_cpu(m->bytes_allocated), - le32_to_cpu(m->bytes_allocated) - 512)) - err = insert_non_resident_attr_in_mft_record(m, AT_DATA, name, - name_len, ic, flags, val, val_len); - else - err = insert_resident_attr_in_mft_record(m, AT_DATA, name, - name_len, ic, flags, 0, val, val_len); - - if (err < 0) - ntfs_log_error("add_attr_data failed: %s\n", strerror(-err)); - return err; -} - -/** - * add_attr_data_positioned - * - * Create a non-resident data attribute with a predefined on disk location - * specified by the runlist @rl. The clusters specified by @rl are assumed to - * be allocated already. - * - * Return 0 on success or -errno on error. - */ -static int add_attr_data_positioned(MFT_RECORD *m, const char *name, - const u32 name_len, const IGNORE_CASE_BOOL ic, - const ATTR_FLAGS flags, const runlist *rl, - const u8 *val, const s64 val_len) -{ - int err; - - err = insert_positioned_attr_in_mft_record(m, AT_DATA, name, name_len, - ic, flags, rl, val, val_len); - if (err < 0) - ntfs_log_error("add_attr_data_positioned failed: %s\n", - strerror(-err)); - return err; -} - -/** - * add_attr_vol_name - * - * Create volume name attribute specifying the volume name @vol_name as a null - * terminated char string of length @vol_name_len (number of characters not - * including the terminating null), which is converted internally to a little - * endian ntfschar string. The name is at least 1 character long and at most - * 0xff characters long (not counting the terminating null). - * - * Return 0 on success or -errno on error. - */ -static int add_attr_vol_name(MFT_RECORD *m, const char *vol_name, - const int vol_name_len __attribute__((unused))) -{ - ntfschar *uname = NULL; - int uname_len = 0; - int i; - - if (vol_name) { - uname_len = ntfs_mbstoucs(vol_name, &uname, 0); - if (uname_len < 0) - return -errno; - if (uname_len > 0xff) { - free(uname); - return -ENAMETOOLONG; - } - } - i = insert_resident_attr_in_mft_record(m, AT_VOLUME_NAME, NULL, 0, 0, - 0, 0, (u8*)uname, uname_len*sizeof(ntfschar)); - free(uname); - if (i < 0) - ntfs_log_error("add_attr_vol_name failed: %s\n", strerror(-i)); - return i; -} - -/** - * add_attr_vol_info - * - * Return 0 on success or -errno on error. - */ -static int add_attr_vol_info(MFT_RECORD *m, const VOLUME_FLAGS flags, - const u8 major_ver, const u8 minor_ver) -{ - VOLUME_INFORMATION vi; - int err; - - memset(&vi, 0, sizeof(vi)); - vi.major_ver = major_ver; - vi.minor_ver = minor_ver; - vi.flags = flags & VOLUME_FLAGS_MASK; - err = insert_resident_attr_in_mft_record(m, AT_VOLUME_INFORMATION, NULL, - 0, 0, 0, 0, (u8*)&vi, sizeof(vi)); - if (err < 0) - ntfs_log_error("add_attr_vol_info failed: %s\n", strerror(-err)); - return err; -} - -/** - * add_attr_index_root - * - * Return 0 on success or -errno on error. - */ -static int add_attr_index_root(MFT_RECORD *m, const char *name, - const u32 name_len, const IGNORE_CASE_BOOL ic, - const ATTR_TYPES indexed_attr_type, - const COLLATION_RULES collation_rule, - const u32 index_block_size) -{ - INDEX_ROOT *r; - INDEX_ENTRY_HEADER *e; - int err, val_len; - - val_len = sizeof(INDEX_ROOT) + sizeof(INDEX_ENTRY_HEADER); - r = ntfs_malloc(val_len); - if (!r) - return -errno; - r->type = (indexed_attr_type == AT_FILE_NAME) ? AT_FILE_NAME : 0; - if (indexed_attr_type == AT_FILE_NAME && - collation_rule != COLLATION_FILE_NAME) { - free(r); - ntfs_log_error("add_attr_index_root: indexed attribute is $FILE_NAME " - "but collation rule is not COLLATION_FILE_NAME.\n"); - return -EINVAL; - } - r->collation_rule = collation_rule; - r->index_block_size = cpu_to_le32(index_block_size); - if (index_block_size >= g_vol->cluster_size) { - if (index_block_size % g_vol->cluster_size) { - ntfs_log_error("add_attr_index_root: index block size is not " - "a multiple of the cluster size.\n"); - free(r); - return -EINVAL; - } - r->clusters_per_index_block = index_block_size / - g_vol->cluster_size; - } else { /* if (g_vol->cluster_size > index_block_size) */ - if (index_block_size & (index_block_size - 1)) { - ntfs_log_error("add_attr_index_root: index block size is not " - "a power of 2.\n"); - free(r); - return -EINVAL; - } - if (index_block_size < (u32)opts.sector_size) { - ntfs_log_error("add_attr_index_root: index block size " - "is smaller than the sector size.\n"); - free(r); - return -EINVAL; - } - r->clusters_per_index_block = index_block_size / - opts.sector_size; - } - memset(&r->reserved, 0, sizeof(r->reserved)); - r->index.entries_offset = const_cpu_to_le32(sizeof(INDEX_HEADER)); - r->index.index_length = const_cpu_to_le32(sizeof(INDEX_HEADER) + - sizeof(INDEX_ENTRY_HEADER)); - r->index.allocated_size = r->index.index_length; - r->index.flags = SMALL_INDEX; - memset(&r->index.reserved, 0, sizeof(r->index.reserved)); - e = (INDEX_ENTRY_HEADER*)((u8*)&r->index + - le32_to_cpu(r->index.entries_offset)); - /* - * No matter whether this is a file index or a view as this is a - * termination entry, hence no key value / data is associated with it - * at all. Thus, we just need the union to be all zero. - */ - e->u.indexed_file = const_cpu_to_le64(0LL); - e->length = const_cpu_to_le16(sizeof(INDEX_ENTRY_HEADER)); - e->key_length = const_cpu_to_le16(0); - e->flags = INDEX_ENTRY_END; - e->reserved = const_cpu_to_le16(0); - err = insert_resident_attr_in_mft_record(m, AT_INDEX_ROOT, name, - name_len, ic, 0, 0, (u8*)r, val_len); - free(r); - if (err < 0) - ntfs_log_error("add_attr_index_root failed: %s\n", strerror(-err)); - return err; -} - -/** - * add_attr_index_alloc - * - * Return 0 on success or -errno on error. - */ -static int add_attr_index_alloc(MFT_RECORD *m, const char *name, - const u32 name_len, const IGNORE_CASE_BOOL ic, - const u8 *index_alloc_val, const u32 index_alloc_val_len) -{ - int err; - - err = insert_non_resident_attr_in_mft_record(m, AT_INDEX_ALLOCATION, - name, name_len, ic, 0, index_alloc_val, - index_alloc_val_len); - if (err < 0) - ntfs_log_error("add_attr_index_alloc failed: %s\n", strerror(-err)); - return err; -} - -/** - * add_attr_bitmap - * - * Return 0 on success or -errno on error. - */ -static int add_attr_bitmap(MFT_RECORD *m, const char *name, const u32 name_len, - const IGNORE_CASE_BOOL ic, const u8 *bitmap, - const u32 bitmap_len) -{ - int err; - - /* Does it fit? NO: create non-resident. YES: create resident. */ - if (le32_to_cpu(m->bytes_in_use) + 24 + bitmap_len > - le32_to_cpu(m->bytes_allocated)) - err = insert_non_resident_attr_in_mft_record(m, AT_BITMAP, name, - name_len, ic, 0, bitmap, bitmap_len); - else - err = insert_resident_attr_in_mft_record(m, AT_BITMAP, name, - name_len, ic, 0, 0, bitmap, bitmap_len); - - if (err < 0) - ntfs_log_error("add_attr_bitmap failed: %s\n", strerror(-err)); - return err; -} - -/** - * add_attr_bitmap_positioned - * - * Create a non-resident bitmap attribute with a predefined on disk location - * specified by the runlist @rl. The clusters specified by @rl are assumed to - * be allocated already. - * - * Return 0 on success or -errno on error. - */ -static int add_attr_bitmap_positioned(MFT_RECORD *m, const char *name, - const u32 name_len, const IGNORE_CASE_BOOL ic, - const runlist *rl, const u8 *bitmap, const u32 bitmap_len) -{ - int err; - - err = insert_positioned_attr_in_mft_record(m, AT_BITMAP, name, name_len, - ic, 0, rl, bitmap, bitmap_len); - if (err < 0) - ntfs_log_error("add_attr_bitmap_positioned failed: %s\n", - strerror(-err)); - return err; -} - - -/** - * upgrade_to_large_index - * - * Create bitmap and index allocation attributes, modify index root - * attribute accordingly and move all of the index entries from the index root - * into the index allocation. - * - * Return 0 on success or -errno on error. - */ -static int upgrade_to_large_index(MFT_RECORD *m, const char *name, - u32 name_len, const IGNORE_CASE_BOOL ic, - INDEX_ALLOCATION **idx) -{ - ntfs_attr_search_ctx *ctx; - ATTR_RECORD *a; - INDEX_ROOT *r; - INDEX_ENTRY *re; - INDEX_ALLOCATION *ia_val = NULL; - ntfschar *uname = NULL; - int uname_len = 0; - u8 bmp[8]; - char *re_start, *re_end; - int i, err, index_block_size; - - uname = ntfs_str2ucs(name, &uname_len); - if (!uname) - return -errno; - - /* Find the index root attribute. */ - ctx = ntfs_attr_get_search_ctx(NULL, m); - if (!ctx) { - ntfs_log_error("Failed to allocate attribute search context.\n"); - ntfs_ucsfree(uname); - return -ENOMEM; - } - if (ic == IGNORE_CASE) { - ntfs_log_error("FIXME: Hit unimplemented code path #4.\n"); - err = -EOPNOTSUPP; - ntfs_ucsfree(uname); - goto err_out; - } - err = mkntfs_attr_lookup(AT_INDEX_ROOT, uname, uname_len, ic, 0, NULL, 0, - ctx); - ntfs_ucsfree(uname); - if (err) { - err = -ENOTDIR; - goto err_out; - } - a = ctx->attr; - if (a->non_resident || a->flags) { - err = -EINVAL; - goto err_out; - } - r = (INDEX_ROOT*)((char*)a + le16_to_cpu(a->u.res.value_offset)); - re_end = (char*)r + le32_to_cpu(a->u.res.value_length); - re_start = (char*)&r->index + le32_to_cpu(r->index.entries_offset); - re = (INDEX_ENTRY*)re_start; - index_block_size = le32_to_cpu(r->index_block_size); - memset(bmp, 0, sizeof(bmp)); - ntfs_bit_set(bmp, 0ULL, 1); - /* Bitmap has to be at least 8 bytes in size. */ - err = add_attr_bitmap(m, name, name_len, ic, bmp, sizeof(bmp)); - if (err) - goto err_out; - ia_val = ntfs_calloc(index_block_size); - if (!ia_val) { - err = -errno; - goto err_out; - } - /* Setup header. */ - ia_val->magic = magic_INDX; - ia_val->usa_ofs = cpu_to_le16(sizeof(INDEX_ALLOCATION)); - if (index_block_size >= NTFS_BLOCK_SIZE) { - ia_val->usa_count = cpu_to_le16(index_block_size / - NTFS_BLOCK_SIZE + 1); - } else { - ia_val->usa_count = cpu_to_le16(1); - ntfs_log_error("Sector size is bigger than index block 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 filesystem created was corrupt. " - "Thank you.", NTFS_DEV_LIST); - } - /* Set USN to 1. */ - *(le16*)((char*)ia_val + le16_to_cpu(ia_val->usa_ofs)) = - cpu_to_le16(1); - ia_val->lsn = 0; - ia_val->index_block_vcn = 0; - ia_val->index.flags = LEAF_NODE; - /* Align to 8-byte boundary. */ - ia_val->index.entries_offset = cpu_to_le32((sizeof(INDEX_HEADER) + - le16_to_cpu(ia_val->usa_count) * 2 + 7) & ~7); - ia_val->index.allocated_size = cpu_to_le32(index_block_size - - (sizeof(INDEX_ALLOCATION) - sizeof(INDEX_HEADER))); - /* Find the last entry in the index root and save it in re. */ - while ((char*)re < re_end && !(re->flags & INDEX_ENTRY_END)) { - /* Next entry in index root. */ - re = (INDEX_ENTRY*)((char*)re + le16_to_cpu(re->length)); - } - /* Copy all the entries including the termination entry. */ - i = (char*)re - re_start + le16_to_cpu(re->length); - memcpy((char*)&ia_val->index + - le32_to_cpu(ia_val->index.entries_offset), re_start, i); - /* Finish setting up index allocation. */ - ia_val->index.index_length = cpu_to_le32(i + - le32_to_cpu(ia_val->index.entries_offset)); - /* Move the termination entry forward to the beginning if necessary. */ - if ((char*)re > re_start) { - memmove(re_start, (char*)re, le16_to_cpu(re->length)); - re = (INDEX_ENTRY*)re_start; - } - /* Now fixup empty index root with pointer to index allocation VCN 0. */ - r->index.flags = LARGE_INDEX; - re->flags |= INDEX_ENTRY_NODE; - if (le16_to_cpu(re->length) < sizeof(INDEX_ENTRY_HEADER) + sizeof(VCN)) - re->length = cpu_to_le16(le16_to_cpu(re->length) + sizeof(VCN)); - r->index.index_length = cpu_to_le32(le32_to_cpu(r->index.entries_offset) - + le16_to_cpu(re->length)); - r->index.allocated_size = r->index.index_length; - /* Resize index root attribute. */ - if (ntfs_resident_attr_value_resize(m, a, sizeof(INDEX_ROOT) - - sizeof(INDEX_HEADER) + - le32_to_cpu(r->index.allocated_size))) { - /* TODO: Remove the added bitmap! */ - /* Revert index root from index allocation. */ - err = -errno; - goto err_out; - } - /* Set VCN pointer to 0LL. */ - *(leVCN*)((char*)re + le16_to_cpu(re->length) - sizeof(VCN)) = 0; - err = ntfs_mst_pre_write_fixup((NTFS_RECORD*)ia_val, index_block_size); - if (err) { - err = -errno; - ntfs_log_error("ntfs_mst_pre_write_fixup() failed in " - "upgrade_to_large_index.\n"); - goto err_out; - } - err = add_attr_index_alloc(m, name, name_len, ic, (u8*)ia_val, - index_block_size); - ntfs_mst_post_write_fixup((NTFS_RECORD*)ia_val); - if (err) { - /* TODO: Remove the added bitmap! */ - /* Revert index root from index allocation. */ - goto err_out; - } - *idx = ia_val; - ntfs_attr_put_search_ctx(ctx); - return 0; -err_out: - ntfs_attr_put_search_ctx(ctx); - free(ia_val); - return err; -} - -/** - * make_room_for_index_entry_in_index_block - * - * Create space of @size bytes at position @pos inside the index block @idx. - * - * Return 0 on success or -errno on error. - */ -static int make_room_for_index_entry_in_index_block(INDEX_BLOCK *idx, - INDEX_ENTRY *pos, u32 size) -{ - u32 biu; - - if (!size) - return 0; -#ifdef DEBUG - /* - * Rigorous consistency checks. Always return -EINVAL even if more - * appropriate codes exist for simplicity of parsing the return value. - */ - if (size != ((size + 7) & ~7)) { - ntfs_log_error("make_room_for_index_entry_in_index_block() received " - "non 8-byte aligned size.\n"); - return -EINVAL; - } - if (!idx || !pos) - return -EINVAL; - if ((char*)pos < (char*)idx || (char*)pos + size < (char*)idx || - (char*)pos > (char*)idx + sizeof(INDEX_BLOCK) - - sizeof(INDEX_HEADER) + - le32_to_cpu(idx->index.allocated_size) || - (char*)pos + size > (char*)idx + sizeof(INDEX_BLOCK) - - sizeof(INDEX_HEADER) + - le32_to_cpu(idx->index.allocated_size)) - return -EINVAL; - /* The - sizeof(INDEX_ENTRY_HEADER) is for the index terminator. */ - if ((char*)pos - (char*)&idx->index > - (int)le32_to_cpu(idx->index.index_length) - - (int)sizeof(INDEX_ENTRY_HEADER)) - return -EINVAL; -#endif - biu = le32_to_cpu(idx->index.index_length); - /* Do we have enough space? */ - if (biu + size > le32_to_cpu(idx->index.allocated_size)) - return -ENOSPC; - /* Move everything after pos to pos + size. */ - memmove((char*)pos + size, (char*)pos, biu - ((char*)pos - - (char*)&idx->index)); - /* Update index block. */ - idx->index.index_length = cpu_to_le32(biu + size); - return 0; -} - -/** - * ntfs_index_keys_compare - * - * not all types of COLLATION_RULES supported yet... - * added as needed.. (remove this comment when all are added) - */ -static int ntfs_index_keys_compare(u8 *key1, u8 *key2, int key1_length, - int key2_length, COLLATION_RULES collation_rule) -{ - u32 u1, u2; - int i; - - if (collation_rule == COLLATION_NTOFS_ULONG) { - /* i.e. $SII or $QUOTA-$Q */ - u1 = le32_to_cpup(key1); - u2 = le32_to_cpup(key2); - if (u1 < u2) - return -1; - if (u1 > u2) - return 1; - /* u1 == u2 */ - return 0; - } - if (collation_rule == COLLATION_NTOFS_ULONGS) { - /* i.e $OBJID-$O */ - i = 0; - while (i < min(key1_length, key2_length)) { - u1 = le32_to_cpup(key1 + i); - u2 = le32_to_cpup(key2 + i); - if (u1 < u2) - return -1; - if (u1 > u2) - return 1; - /* u1 == u2 */ - i += sizeof(u32); - } - if (key1_length < key2_length) - return -1; - if (key1_length > key2_length) - return 1; - return 0; - } - if (collation_rule == COLLATION_NTOFS_SECURITY_HASH) { - /* i.e. $SDH */ - u1 = le32_to_cpu(((SDH_INDEX_KEY*)key1)->hash); - u2 = le32_to_cpu(((SDH_INDEX_KEY*)key2)->hash); - if (u1 < u2) - return -1; - if (u1 > u2) - return 1; - /* u1 == u2 */ - u1 = le32_to_cpu(((SDH_INDEX_KEY*)key1)->security_id); - u2 = le32_to_cpu(((SDH_INDEX_KEY*)key2)->security_id); - if (u1 < u2) - return -1; - if (u1 > u2) - return 1; - return 0; - } - if (collation_rule == COLLATION_NTOFS_SID) { - /* i.e. $QUOTA-O */ - i = memcmp(key1, key2, min(key1_length, key2_length)); - if (!i) { - if (key1_length < key2_length) - return -1; - if (key1_length > key2_length) - return 1; - } - return i; - } - ntfs_log_critical("ntfs_index_keys_compare called without supported " - "collation rule.\n"); - return 0; /* Claim they're equal. What else can we do? */ -} - -/** - * insert_index_entry_in_res_dir_index - * - * i.e. insert an index_entry in some named index_root - * simplified search method, works for mkntfs - */ -static int insert_index_entry_in_res_dir_index(INDEX_ENTRY *idx, u32 idx_size, - MFT_RECORD *m, ntfschar *name, u32 name_size, ATTR_TYPES type) -{ - ntfs_attr_search_ctx *ctx; - INDEX_HEADER *idx_header; - INDEX_ENTRY *idx_entry, *idx_end; - ATTR_RECORD *a; - COLLATION_RULES collation_rule; - int err, i; - - err = 0; - /* does it fit ?*/ - if (g_vol->mft_record_size > idx_size + le32_to_cpu(m->bytes_allocated)) - return -ENOSPC; - /* find the INDEX_ROOT attribute:*/ - ctx = ntfs_attr_get_search_ctx(NULL, m); - if (!ctx) { - ntfs_log_error("Failed to allocate attribute search " - "context.\n"); - err = -ENOMEM; - goto err_out; - } - if (mkntfs_attr_lookup(AT_INDEX_ROOT, name, name_size, 0, 0, NULL, 0, - ctx)) { - err = -EEXIST; - goto err_out; - } - /* found attribute */ - a = (ATTR_RECORD*)ctx->attr; - collation_rule = ((INDEX_ROOT*)((u8*)a + - le16_to_cpu(a->u.res.value_offset)))->collation_rule; - idx_header = (INDEX_HEADER*)((u8*)a + le16_to_cpu(a->u.res.value_offset) - + 0x10); - idx_entry = (INDEX_ENTRY*)((u8*)idx_header + - le32_to_cpu(idx_header->entries_offset)); - idx_end = (INDEX_ENTRY*)((u8*)idx_entry + - le32_to_cpu(idx_header->index_length)); - /* - * Loop until we exceed valid memory (corruption case) or until we - * reach the last entry. - */ - if (type == AT_FILE_NAME) { - while (((u8*)idx_entry < (u8*)idx_end) && - !(idx_entry->flags & INDEX_ENTRY_END)) { - i = ntfs_file_values_compare(&idx->key.file_name, - &idx_entry->key.file_name, 1, - IGNORE_CASE, g_vol->upcase, - g_vol->upcase_len); - /* - * If @file_name collates before ie->key.file_name, - * there is no matching index entry. - */ - if (i == -1) - break; - /* If file names are not equal, continue search. */ - if (i) - goto do_next; - if (idx->key.file_name.file_name_type != - FILE_NAME_POSIX || - idx_entry->key.file_name.file_name_type - != FILE_NAME_POSIX) - return -EEXIST; - i = ntfs_file_values_compare(&idx->key.file_name, - &idx_entry->key.file_name, 1, - CASE_SENSITIVE, g_vol->upcase, - g_vol->upcase_len); - if (!i) - return -EEXIST; - if (i == -1) - break; -do_next: - idx_entry = (INDEX_ENTRY*)((u8*)idx_entry + - le16_to_cpu(idx_entry->length)); - } - } else if (type == AT_UNUSED) { /* case view */ - while (((u8*)idx_entry < (u8*)idx_end) && - !(idx_entry->flags & INDEX_ENTRY_END)) { - i = ntfs_index_keys_compare((u8*)idx + 0x10, - (u8*)idx_entry + 0x10, - le16_to_cpu(idx->key_length), - le16_to_cpu(idx_entry->key_length), - collation_rule); - if (!i) - return -EEXIST; - if (i == -1) - break; - idx_entry = (INDEX_ENTRY*)((u8*)idx_entry + - le16_to_cpu(idx_entry->length)); - } - } else - return -EINVAL; - memmove((u8*)idx_entry + idx_size, (u8*)idx_entry, - le32_to_cpu(m->bytes_in_use) - - ((u8*)idx_entry - (u8*)m)); - memcpy((u8*)idx_entry, (u8*)idx, idx_size); - /* Adjust various offsets, etc... */ - m->bytes_in_use = cpu_to_le32(le32_to_cpu(m->bytes_in_use) + idx_size); - a->length = cpu_to_le32(le32_to_cpu(a->length) + idx_size); - a->u.res.value_length = cpu_to_le32(le32_to_cpu(a->u.res.value_length) + idx_size); - idx_header->index_length = cpu_to_le32( - le32_to_cpu(idx_header->index_length) + idx_size); - idx_header->allocated_size = cpu_to_le32( - le32_to_cpu(idx_header->allocated_size) + idx_size); -err_out: - if (ctx) - ntfs_attr_put_search_ctx(ctx); - return err; -} - -/** - * initialize_secure - * - * initializes $Secure's $SDH and $SII indexes from $SDS datastream - */ -static int initialize_secure(char *sds, u32 sds_size, MFT_RECORD *m) -{ - int err, sdh_size, sii_size; - SECURITY_DESCRIPTOR_HEADER *sds_header; - INDEX_ENTRY *idx_entry_sdh, *idx_entry_sii; - SDH_INDEX_DATA *sdh_data; - SII_INDEX_DATA *sii_data; - - sds_header = (SECURITY_DESCRIPTOR_HEADER*)sds; - sdh_size = sizeof(INDEX_ENTRY_HEADER); - sdh_size += sizeof(SDH_INDEX_KEY) + sizeof(SDH_INDEX_DATA); - sii_size = sizeof(INDEX_ENTRY_HEADER); - sii_size += sizeof(SII_INDEX_KEY) + sizeof(SII_INDEX_DATA); - idx_entry_sdh = ntfs_calloc(sizeof(INDEX_ENTRY)); - if (!idx_entry_sdh) - return -errno; - idx_entry_sii = ntfs_calloc(sizeof(INDEX_ENTRY)); - if (!idx_entry_sii) { - free(idx_entry_sdh); - return -errno; - } - err = 0; - - while ((char*)sds_header < (char*)sds + sds_size) { - if (!sds_header->length) - break; - /* SDH index entry */ - idx_entry_sdh->u.s.data_offset = const_cpu_to_le16(0x18); - idx_entry_sdh->u.s.data_length = const_cpu_to_le16(0x14); - idx_entry_sdh->u.s.reservedV = const_cpu_to_le32(0x00); - idx_entry_sdh->length = const_cpu_to_le16(0x30); - idx_entry_sdh->key_length = const_cpu_to_le16(0x08); - idx_entry_sdh->flags = const_cpu_to_le16(0x00); - idx_entry_sdh->reserved = const_cpu_to_le16(0x00); - idx_entry_sdh->key.sdh.hash = sds_header->hash; - idx_entry_sdh->key.sdh.security_id = sds_header->security_id; - sdh_data = (SDH_INDEX_DATA*)((u8*)idx_entry_sdh + - le16_to_cpu(idx_entry_sdh->u.s.data_offset)); - sdh_data->hash = sds_header->hash; - sdh_data->security_id = sds_header->security_id; - sdh_data->offset = sds_header->offset; - sdh_data->length = sds_header->length; - sdh_data->reserved_II = const_cpu_to_le32(0x00490049); - - /* SII index entry */ - idx_entry_sii->u.s.data_offset = const_cpu_to_le16(0x14); - idx_entry_sii->u.s.data_length = const_cpu_to_le16(0x14); - idx_entry_sii->u.s.reservedV = const_cpu_to_le32(0x00); - idx_entry_sii->length = const_cpu_to_le16(0x28); - idx_entry_sii->key_length = const_cpu_to_le16(0x04); - idx_entry_sii->flags = const_cpu_to_le16(0x00); - idx_entry_sii->reserved = const_cpu_to_le16(0x00); - idx_entry_sii->key.sii.security_id = sds_header->security_id; - sii_data = (SII_INDEX_DATA*)((u8*)idx_entry_sii + - le16_to_cpu(idx_entry_sii->u.s.data_offset)); - sii_data->hash = sds_header->hash; - sii_data->security_id = sds_header->security_id; - sii_data->offset = sds_header->offset; - sii_data->length = sds_header->length; - if ((err = insert_index_entry_in_res_dir_index(idx_entry_sdh, - sdh_size, m, NTFS_INDEX_SDH, 4, AT_UNUSED))) - break; - if ((err = insert_index_entry_in_res_dir_index(idx_entry_sii, - sii_size, m, NTFS_INDEX_SII, 4, AT_UNUSED))) - break; - sds_header = (SECURITY_DESCRIPTOR_HEADER*)((u8*)sds_header + - ((le32_to_cpu(sds_header->length) + 15) & ~15)); - } - free(idx_entry_sdh); - free(idx_entry_sii); - return err; -} - -/** - * initialize_quota - * - * initialize $Quota with the default quota index-entries. - */ -static int initialize_quota(MFT_RECORD *m) -{ - int o_size, q1_size, q2_size, err, i; - INDEX_ENTRY *idx_entry_o, *idx_entry_q1, *idx_entry_q2; - QUOTA_O_INDEX_DATA *idx_entry_o_data; - QUOTA_CONTROL_ENTRY *idx_entry_q1_data, *idx_entry_q2_data; - - err = 0; - /* q index entry num 1 */ - q1_size = 0x48; - idx_entry_q1 = ntfs_calloc(q1_size); - if (!idx_entry_q1) - return errno; - idx_entry_q1->u.s.data_offset = const_cpu_to_le16(0x14); - idx_entry_q1->u.s.data_length = const_cpu_to_le16(0x30); - idx_entry_q1->u.s.reservedV = const_cpu_to_le32(0x00); - idx_entry_q1->length = const_cpu_to_le16(0x48); - idx_entry_q1->key_length = const_cpu_to_le16(0x04); - idx_entry_q1->flags = const_cpu_to_le16(0x00); - idx_entry_q1->reserved = const_cpu_to_le16(0x00); - idx_entry_q1->key.owner_id = const_cpu_to_le32(0x01); - idx_entry_q1_data = (QUOTA_CONTROL_ENTRY*)((char*)idx_entry_q1 - + le16_to_cpu(idx_entry_q1->u.s.data_offset)); - idx_entry_q1_data->version = const_cpu_to_le32(0x02); - idx_entry_q1_data->flags = QUOTA_FLAG_DEFAULT_LIMITS; - idx_entry_q1_data->bytes_used = const_cpu_to_le64(0x00); - idx_entry_q1_data->change_time = utc2ntfs(mkntfs_time()); - idx_entry_q1_data->threshold = cpu_to_sle64(-1); - idx_entry_q1_data->limit = cpu_to_sle64(-1); - idx_entry_q1_data->exceeded_time = 0; - err = insert_index_entry_in_res_dir_index(idx_entry_q1, q1_size, m, - NTFS_INDEX_Q, 2, AT_UNUSED); - free(idx_entry_q1); - if (err) - return err; - /* q index entry num 2 */ - q2_size = 0x58; - idx_entry_q2 = ntfs_calloc(q2_size); - if (!idx_entry_q2) - return errno; - idx_entry_q2->u.s.data_offset = const_cpu_to_le16(0x14); - idx_entry_q2->u.s.data_length = const_cpu_to_le16(0x40); - idx_entry_q2->u.s.reservedV = const_cpu_to_le32(0x00); - idx_entry_q2->length = const_cpu_to_le16(0x58); - idx_entry_q2->key_length = const_cpu_to_le16(0x04); - idx_entry_q2->flags = const_cpu_to_le16(0x00); - idx_entry_q2->reserved = const_cpu_to_le16(0x00); - idx_entry_q2->key.owner_id = QUOTA_FIRST_USER_ID; - idx_entry_q2_data = (QUOTA_CONTROL_ENTRY*)((char*)idx_entry_q2 - + le16_to_cpu(idx_entry_q2->u.s.data_offset)); - idx_entry_q2_data->version = const_cpu_to_le32(0x02); - idx_entry_q2_data->flags = QUOTA_FLAG_DEFAULT_LIMITS; - idx_entry_q2_data->bytes_used = const_cpu_to_le64(0x00); - idx_entry_q2_data->change_time = utc2ntfs(mkntfs_time());; - idx_entry_q2_data->threshold = cpu_to_sle64(-1); - idx_entry_q2_data->limit = cpu_to_sle64(-1); - idx_entry_q2_data->exceeded_time = 0; - idx_entry_q2_data->sid.revision = 1; - idx_entry_q2_data->sid.sub_authority_count = 2; - for (i = 0; i < 5; i++) - idx_entry_q2_data->sid.identifier_authority.value[i] = 0; - idx_entry_q2_data->sid.identifier_authority.value[5] = 0x05; - idx_entry_q2_data->sid.sub_authority[0] = - const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID); - idx_entry_q2_data->sid.sub_authority[1] = - const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS); - err = insert_index_entry_in_res_dir_index(idx_entry_q2, q2_size, m, - NTFS_INDEX_Q, 2, AT_UNUSED); - free(idx_entry_q2); - if (err) - return err; - o_size = 0x28; - idx_entry_o = ntfs_calloc(o_size); - if (!idx_entry_o) - return errno; - idx_entry_o->u.s.data_offset = const_cpu_to_le16(0x20); - idx_entry_o->u.s.data_length = const_cpu_to_le16(0x04); - idx_entry_o->u.s.reservedV = const_cpu_to_le32(0x00); - idx_entry_o->length = const_cpu_to_le16(0x28); - idx_entry_o->key_length = const_cpu_to_le16(0x10); - idx_entry_o->flags = const_cpu_to_le16(0x00); - idx_entry_o->reserved = const_cpu_to_le16(0x00); - idx_entry_o->key.sid.revision = 0x01; - idx_entry_o->key.sid.sub_authority_count = 0x02; - for (i = 0; i < 5; i++) - idx_entry_o->key.sid.identifier_authority.value[i] = 0; - idx_entry_o->key.sid.identifier_authority.value[5] = 0x05; - idx_entry_o->key.sid.sub_authority[0] = - const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID); - idx_entry_o->key.sid.sub_authority[1] = - const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS); - idx_entry_o_data = (QUOTA_O_INDEX_DATA*)((char*)idx_entry_o - + le16_to_cpu(idx_entry_o->u.s.data_offset)); - idx_entry_o_data->owner_id = QUOTA_FIRST_USER_ID; - /* 20 00 00 00 padding after here on ntfs 3.1. 3.0 is unchecked. */ - idx_entry_o_data->unknown = const_cpu_to_le32(32); - err = insert_index_entry_in_res_dir_index(idx_entry_o, o_size, m, - NTFS_INDEX_O, 2, AT_UNUSED); - free(idx_entry_o); - - return err; -} - -/** - * insert_file_link_in_dir_index - * - * Insert the fully completed FILE_NAME_ATTR @file_name which is inside - * the file with mft reference @file_ref into the index (allocation) block - * @idx (which belongs to @file_ref's parent directory). - * - * Return 0 on success or -errno on error. - */ -static int insert_file_link_in_dir_index(INDEX_BLOCK *idx, leMFT_REF file_ref, - FILE_NAME_ATTR *file_name, u32 file_name_size) -{ - int err, i; - INDEX_ENTRY *ie; - char *index_end; - - /* - * Lookup dir entry @file_name in dir @idx to determine correct - * insertion location. FIXME: Using a very oversimplified lookup - * method which is sufficient for mkntfs but no good whatsoever in - * real world scenario. (AIA) - */ - - index_end = (char*)&idx->index + le32_to_cpu(idx->index.index_length); - ie = (INDEX_ENTRY*)((char*)&idx->index + - le32_to_cpu(idx->index.entries_offset)); - /* - * Loop until we exceed valid memory (corruption case) or until we - * reach the last entry. - */ - while ((char*)ie < index_end && !(ie->flags & INDEX_ENTRY_END)) { -#if 0 -#ifdef DEBUG - ntfs_log_debug("file_name_attr1->file_name_length = %i\n", - file_name->file_name_length); - if (file_name->file_name_length) { - char *__buf = NULL; - i = ntfs_ucstombs((ntfschar*)&file_name->file_name, - file_name->file_name_length, &__buf, 0); - if (i < 0) - ntfs_log_debug("Name contains non-displayable " - "Unicode characters.\n"); - ntfs_log_debug("file_name_attr1->file_name = %s\n", - __buf); - free(__buf); - } - ntfs_log_debug("file_name_attr2->file_name_length = %i\n", - ie->key.file_name.file_name_length); - if (ie->key.file_name.file_name_length) { - char *__buf = NULL; - i = ntfs_ucstombs(ie->key.file_name.file_name, - ie->key.file_name.file_name_length + 1, &__buf, - 0); - if (i < 0) - ntfs_log_debug("Name contains non-displayable " - "Unicode characters.\n"); - ntfs_log_debug("file_name_attr2->file_name = %s\n", - __buf); - free(__buf); - } -#endif -#endif - i = ntfs_file_values_compare(file_name, - (FILE_NAME_ATTR*)&ie->key.file_name, 1, - IGNORE_CASE, g_vol->upcase, g_vol->upcase_len); - /* - * If @file_name collates before ie->key.file_name, there is no - * matching index entry. - */ - if (i == -1) - break; - /* If file names are not equal, continue search. */ - if (i) - goto do_next; - /* File names are equal when compared ignoring case. */ - /* - * If BOTH file names are in the POSIX namespace, do a case - * sensitive comparison as well. Otherwise the names match so - * we return -EEXIST. FIXME: There are problems with this in a - * real world scenario, when one is POSIX and one isn't, but - * fine for mkntfs where we don't use POSIX namespace at all - * and hence this following code is luxury. (AIA) - */ - if (file_name->file_name_type != FILE_NAME_POSIX || - ie->key.file_name.file_name_type != FILE_NAME_POSIX) - return -EEXIST; - i = ntfs_file_values_compare(file_name, - (FILE_NAME_ATTR*)&ie->key.file_name, 1, - CASE_SENSITIVE, g_vol->upcase, - g_vol->upcase_len); - if (i == -1) - break; - /* Complete match. Bugger. Can't insert. */ - if (!i) - return -EEXIST; -do_next: -#ifdef DEBUG - /* Next entry. */ - if (!ie->length) { - ntfs_log_debug("BUG: ie->length is zero, breaking out " - "of loop.\n"); - break; - } -#endif - ie = (INDEX_ENTRY*)((char*)ie + le16_to_cpu(ie->length)); - }; - i = (sizeof(INDEX_ENTRY_HEADER) + file_name_size + 7) & ~7; - err = make_room_for_index_entry_in_index_block(idx, ie, i); - if (err) { - ntfs_log_error("make_room_for_index_entry_in_index_block " - "failed: %s\n", strerror(-err)); - return err; - } - /* Create entry in place and copy file name attribute value. */ - ie->u.indexed_file = file_ref; - ie->length = cpu_to_le16(i); - ie->key_length = cpu_to_le16(file_name_size); - ie->flags = cpu_to_le16(0); - ie->reserved = cpu_to_le16(0); - memcpy((char*)&ie->key.file_name, (char*)file_name, file_name_size); - return 0; -} - -/** - * create_hardlink_res - * - * Create a file_name_attribute in the mft record @m_file which points to the - * parent directory with mft reference @ref_parent. - * - * Then, insert an index entry with this file_name_attribute in the index - * root @idx of the index_root attribute of the parent directory. - * - * @ref_file is the mft reference of @m_file. - * - * Return 0 on success or -errno on error. - */ -static int create_hardlink_res(MFT_RECORD *m_parent, const leMFT_REF ref_parent, - MFT_RECORD *m_file, const leMFT_REF ref_file, - const s64 allocated_size, const s64 data_size, - const FILE_ATTR_FLAGS flags, const u16 packed_ea_size, - const u32 reparse_point_tag, const char *file_name, - const FILE_NAME_TYPE_FLAGS file_name_type) -{ - FILE_NAME_ATTR *fn; - int i, fn_size, idx_size; - INDEX_ENTRY *idx_entry_new; - ntfschar *uname; - - /* Create the file_name attribute. */ - i = (strlen(file_name) + 1) * sizeof(ntfschar); - fn_size = sizeof(FILE_NAME_ATTR) + i; - fn = ntfs_malloc(fn_size); - if (!fn) - return -errno; - fn->parent_directory = ref_parent; - /* FIXME: copy the creation_time from the std info */ - fn->creation_time = utc2ntfs(mkntfs_time()); - fn->last_data_change_time = fn->creation_time; - fn->last_mft_change_time = fn->creation_time; - fn->last_access_time = fn->creation_time; - fn->allocated_size = cpu_to_sle64(allocated_size); - fn->data_size = cpu_to_sle64(data_size); - fn->file_attributes = flags; - /* These are in a union so can't have both. */ - if (packed_ea_size && reparse_point_tag) { - free(fn); - return -EINVAL; - } - if (packed_ea_size) { - free(fn); - return -EINVAL; - } - if (packed_ea_size) { - fn->u.s.packed_ea_size = cpu_to_le16(packed_ea_size); - fn->u.s.reserved = cpu_to_le16(0); - } else { - fn->u.reparse_point_tag = cpu_to_le32(reparse_point_tag); - } - fn->file_name_type = file_name_type; - uname = fn->file_name; - i = ntfs_mbstoucs(file_name, &uname, i); - if (i < 1) { - free(fn); - return -EINVAL; - } - if (i > 0xff) { - free(fn); - return -ENAMETOOLONG; - } - /* No terminating null in file names. */ - fn->file_name_length = i; - fn_size = sizeof(FILE_NAME_ATTR) + i * sizeof(ntfschar); - /* Increment the link count of @m_file. */ - i = le16_to_cpu(m_file->link_count); - if (i == 0xffff) { - ntfs_log_error("Too many hardlinks present already.\n"); - free(fn); - return -EINVAL; - } - m_file->link_count = cpu_to_le16(i + 1); - /* Add the file_name to @m_file. */ - i = insert_resident_attr_in_mft_record(m_file, AT_FILE_NAME, NULL, 0, 0, - 0, RESIDENT_ATTR_IS_INDEXED, (u8*)fn, fn_size); - if (i < 0) { - ntfs_log_error("create_hardlink failed adding file name " - "attribute: %s\n", strerror(-i)); - free(fn); - /* Undo link count increment. */ - m_file->link_count = cpu_to_le16( - le16_to_cpu(m_file->link_count) - 1); - return i; - } - /* Insert the index entry for file_name in @idx. */ - idx_size = (fn_size + 7) & ~7; - idx_entry_new = ntfs_calloc(idx_size + 0x10); - if (!idx_entry_new) - return -errno; - idx_entry_new->u.indexed_file = ref_file; - idx_entry_new->length = cpu_to_le16(idx_size + 0x10); - idx_entry_new->key_length = cpu_to_le16(fn_size); - memcpy((u8*)idx_entry_new + 0x10, (u8*)fn, fn_size); - i = insert_index_entry_in_res_dir_index(idx_entry_new, idx_size + 0x10, - m_parent, NTFS_INDEX_I30, 4, AT_FILE_NAME); - if (i < 0) { - ntfs_log_error("create_hardlink failed inserting index entry: " - "%s\n", strerror(-i)); - /* FIXME: Remove the file name attribute from @m_file. */ - free(idx_entry_new); - free(fn); - /* Undo link count increment. */ - m_file->link_count = cpu_to_le16( - le16_to_cpu(m_file->link_count) - 1); - return i; - } - free(idx_entry_new); - free(fn); - return 0; -} - -/** - * create_hardlink - * - * Create a file_name_attribute in the mft record @m_file which points to the - * parent directory with mft reference @ref_parent. - * - * Then, insert an index entry with this file_name_attribute in the index - * block @idx of the index allocation attribute of the parent directory. - * - * @ref_file is the mft reference of @m_file. - * - * Return 0 on success or -errno on error. - */ -static int create_hardlink(INDEX_BLOCK *idx, const leMFT_REF ref_parent, - MFT_RECORD *m_file, const leMFT_REF ref_file, - const s64 allocated_size, const s64 data_size, - const FILE_ATTR_FLAGS flags, const u16 packed_ea_size, - const u32 reparse_point_tag, const char *file_name, - const FILE_NAME_TYPE_FLAGS file_name_type) -{ - FILE_NAME_ATTR *fn; - int i, fn_size; - ntfschar *uname; - - /* Create the file_name attribute. */ - i = (strlen(file_name) + 1) * sizeof(ntfschar); - fn_size = sizeof(FILE_NAME_ATTR) + i; - fn = ntfs_malloc(fn_size); - if (!fn) - return -errno; - fn->parent_directory = ref_parent; - /* FIXME: Is this correct? Or do we have to copy the creation_time */ - /* from the std info? */ - fn->creation_time = utc2ntfs(mkntfs_time()); - fn->last_data_change_time = fn->creation_time; - fn->last_mft_change_time = fn->creation_time; - fn->last_access_time = fn->creation_time; - fn->allocated_size = cpu_to_sle64(allocated_size); - fn->data_size = cpu_to_sle64(data_size); - fn->file_attributes = flags; - /* These are in a union so can't have both. */ - if (packed_ea_size && reparse_point_tag) { - free(fn); - return -EINVAL; - } - if (packed_ea_size) { - fn->u.s.packed_ea_size = cpu_to_le16(packed_ea_size); - fn->u.s.reserved = cpu_to_le16(0); - } else { - fn->u.reparse_point_tag = cpu_to_le32(reparse_point_tag); - } - fn->file_name_type = file_name_type; - uname = fn->file_name; - i = ntfs_mbstoucs(file_name, &uname, i); - if (i < 1) { - free(fn); - return -EINVAL; - } - if (i > 0xff) { - free(fn); - return -ENAMETOOLONG; - } - /* No terminating null in file names. */ - fn->file_name_length = i; - fn_size = sizeof(FILE_NAME_ATTR) + i * sizeof(ntfschar); - /* Increment the link count of @m_file. */ - i = le16_to_cpu(m_file->link_count); - if (i == 0xffff) { - ntfs_log_error("Too many hardlinks present already.\n"); - free(fn); - return -EINVAL; - } - m_file->link_count = cpu_to_le16(i + 1); - /* Add the file_name to @m_file. */ - i = insert_resident_attr_in_mft_record(m_file, AT_FILE_NAME, NULL, 0, 0, - 0, RESIDENT_ATTR_IS_INDEXED, (u8*)fn, fn_size); - if (i < 0) { - ntfs_log_error("create_hardlink failed adding file name attribute: " - "%s\n", strerror(-i)); - free(fn); - /* Undo link count increment. */ - m_file->link_count = cpu_to_le16( - le16_to_cpu(m_file->link_count) - 1); - return i; - } - /* Insert the index entry for file_name in @idx. */ - i = insert_file_link_in_dir_index(idx, ref_file, fn, fn_size); - if (i < 0) { - ntfs_log_error("create_hardlink failed inserting index entry: %s\n", - strerror(-i)); - /* FIXME: Remove the file name attribute from @m_file. */ - free(fn); - /* Undo link count increment. */ - m_file->link_count = cpu_to_le16( - le16_to_cpu(m_file->link_count) - 1); - return i; - } - free(fn); - return 0; -} - -#ifdef ENABLE_UUID - -/** - * index_obj_id_insert - * - * Insert an index entry with the key @guid and data pointing to the mft record - * @ref in the $O index root of the mft record @m (which must be the mft record - * for $ObjId). - * - * Return 0 on success or -errno on error. - */ -static int index_obj_id_insert(MFT_RECORD *m, const GUID *guid, - const leMFT_REF ref) -{ - INDEX_ENTRY *idx_entry_new; - int data_ofs, idx_size, err; - OBJ_ID_INDEX_DATA *oi; - - /* - * Insert the index entry for the object id in the index. - * - * First determine the size of the index entry to be inserted. This - * consists of the index entry header, followed by the index key, i.e. - * the GUID, followed by the index data, i.e. OBJ_ID_INDEX_DATA. - */ - data_ofs = (sizeof(INDEX_ENTRY_HEADER) + sizeof(GUID) + 7) & ~7; - idx_size = (data_ofs + sizeof(OBJ_ID_INDEX_DATA) + 7) & ~7; - idx_entry_new = ntfs_calloc(idx_size); - if (!idx_entry_new) - return -errno; - idx_entry_new->u.s.data_offset = cpu_to_le16(data_ofs); - idx_entry_new->u.s.data_length = cpu_to_le16(sizeof(OBJ_ID_INDEX_DATA)); - idx_entry_new->length = cpu_to_le16(idx_size); - idx_entry_new->key_length = cpu_to_le16(sizeof(GUID)); - idx_entry_new->key.object_id = *guid; - oi = (OBJ_ID_INDEX_DATA*)((u8*)idx_entry_new + data_ofs); - oi->mft_reference = ref; - err = insert_index_entry_in_res_dir_index(idx_entry_new, idx_size, m, - NTFS_INDEX_O, 2, AT_UNUSED); - free(idx_entry_new); - if (err < 0) { - ntfs_log_error("index_obj_id_insert failed inserting index " - "entry: %s\n", strerror(-err)); - return err; - } - return 0; -} - -#endif - -/** - * mkntfs_cleanup - */ -static void mkntfs_cleanup(void) -{ - /* Close the volume */ - if (g_vol) { - if (g_vol->u.dev) { - if (NDevOpen(g_vol->u.dev) && g_vol->u.dev->d_ops->close(g_vol->u.dev)) - ntfs_log_perror("Warning: Could not close %s", g_vol->u.dev->d_name); - ntfs_device_free(g_vol->u.dev); - } - free(g_vol->vol_name); - free(g_vol->attrdef); - free(g_vol->upcase); - free(g_vol); - g_vol = NULL; - } - - /* Free any memory we've used */ - free(g_bad_blocks); g_bad_blocks = NULL; - free(g_buf); g_buf = NULL; - free(g_index_block); g_index_block = NULL; - free(g_lcn_bitmap); g_lcn_bitmap = NULL; - free(g_mft_bitmap); g_mft_bitmap = NULL; - free(g_rl_bad); g_rl_bad = NULL; - free(g_rl_boot); g_rl_boot = NULL; - free(g_rl_logfile); g_rl_logfile = NULL; - free(g_rl_mft); g_rl_mft = NULL; - free(g_rl_mft_bmp); g_rl_mft_bmp = NULL; - free(g_rl_mftmirr); g_rl_mftmirr = NULL; -} - - -/** - * mkntfs_open_partition - - */ -static BOOL mkntfs_open_partition(ntfs_volume *vol) -{ - BOOL result = FALSE; - int i; - struct stat sbuf; - unsigned long mnt_flags; - - /* - * Allocate and initialize an ntfs device structure and attach it to - * the volume. - */ - vol->u.dev = ntfs_device_alloc(opts.dev_name, 0, &ntfs_device_default_io_ops, NULL); - if (!vol->u.dev) { - ntfs_log_perror("Could not create device"); - goto done; - } - - /* Open the device for reading or reading and writing. */ - if (opts.no_action) { - ntfs_log_quiet("Running in READ-ONLY mode!\n"); - i = O_RDONLY; - } else { - i = O_RDWR; - } - if (vol->u.dev->d_ops->open(vol->u.dev, i)) { - if (errno == ENOENT) - ntfs_log_error("The device doesn't exist; did you specify it correctly?\n"); - else - ntfs_log_perror("Could not open %s", vol->u.dev->d_name); - goto done; - } - /* Verify we are dealing with a block device. */ - if (vol->u.dev->d_ops->stat(vol->u.dev, &sbuf)) { - ntfs_log_perror("Error getting information about %s", vol->u.dev->d_name); - goto done; - } - - if (!S_ISBLK(sbuf.st_mode)) { - ntfs_log_error("%s is not a block device.\n", vol->u.dev->d_name); - if (!opts.force) { - ntfs_log_error("Refusing to make a filesystem here!\n"); - goto done; - } - if (!opts.num_sectors) { - if (!sbuf.st_size && !sbuf.st_blocks) { - ntfs_log_error("You must specify the number of sectors.\n"); - goto done; - } - if (opts.sector_size) { - if (sbuf.st_size) - opts.num_sectors = sbuf.st_size / opts.sector_size; - else - opts.num_sectors = ((s64)sbuf.st_blocks << 9) / opts.sector_size; - } else { - if (sbuf.st_size) - opts.num_sectors = sbuf.st_size / 512; - else - opts.num_sectors = sbuf.st_blocks; - opts.sector_size = 512; - } - } - ntfs_log_warning("mkntfs forced anyway.\n"); -#ifdef HAVE_LINUX_MAJOR_H - } else if ((IDE_DISK_MAJOR(MAJOR(sbuf.st_rdev)) && - MINOR(sbuf.st_rdev) % 64 == 0) || - (SCSI_DISK_MAJOR(MAJOR(sbuf.st_rdev)) && - MINOR(sbuf.st_rdev) % 16 == 0)) { - ntfs_log_error("%s is entire device, not just one partition.\n", vol->u.dev->d_name); - if (!opts.force) { - ntfs_log_error("Refusing to make a filesystem here!\n"); - goto done; - } - ntfs_log_warning("mkntfs forced anyway.\n"); -#endif - } - /* Make sure the file system is not mounted. */ - if (ntfs_check_if_mounted(vol->u.dev->d_name, &mnt_flags)) { - ntfs_log_perror("Failed to determine whether %s is mounted", vol->u.dev->d_name); - } else if (mnt_flags & NTFS_MF_MOUNTED) { - ntfs_log_error("%s is mounted.\n", vol->u.dev->d_name); - if (!opts.force) { - ntfs_log_error("Refusing to make a filesystem here!\n"); - goto done; - } - ntfs_log_warning("mkntfs forced anyway. Hope /etc/mtab is incorrect.\n"); - } - result = TRUE; -done: - return result; -} - -/** - * mkntfs_get_page_size - detect the system's memory page size. - */ -static long mkntfs_get_page_size(void) -{ - long page_size; -#ifdef _SC_PAGESIZE - page_size = sysconf(_SC_PAGESIZE); - if (page_size < 0) -#endif -#ifdef _SC_PAGE_SIZE - page_size = sysconf(_SC_PAGE_SIZE); - if (page_size < 0) -#endif - { - ntfs_log_warning("Failed to determine system page size. " - "Assuming safe default of 4096 bytes.\n"); - return 4096; - } - ntfs_log_debug("System page size is %li bytes.\n", page_size); - return page_size; -} - -/** - * mkntfs_override_vol_params - - */ -static BOOL mkntfs_override_vol_params(ntfs_volume *vol) -{ - s64 volume_size; - long page_size; - int i; - BOOL winboot = TRUE; - - /* If user didn't specify the sector size, determine it now. */ - if (opts.sector_size < 0) { - opts.sector_size = ntfs_device_sector_size_get(vol->u.dev); - if (opts.sector_size < 0) { - ntfs_log_warning("The sector size was not specified " - "for %s and it could not be obtained " - "automatically. It has been set to 512 " - "bytes.\n", vol->u.dev->d_name); - opts.sector_size = 512; - } - } - /* Validate sector size. */ - if ((opts.sector_size - 1) & opts.sector_size) { - ntfs_log_error("The sector size is invalid. It must be a " - "power of two, e.g. 512, 1024.\n"); - return FALSE; - } - if (opts.sector_size < 256 || opts.sector_size > 4096) { - ntfs_log_error("The sector size is invalid. The minimum size " - "is 256 bytes and the maximum is 4096 bytes.\n"); - return FALSE; - } - ntfs_log_debug("sector size = %ld bytes\n", opts.sector_size); - /* Now set the device block size to the sector size. */ - if (ntfs_device_block_size_set(vol->u.dev, opts.sector_size)) - ntfs_log_debug("Failed to set the device block size to the " - "sector size. This may cause problems when " - "creating the backup boot sector and also may " - "affect performance but should be harmless " - "otherwise. Error: %s\n", strerror(errno)); - /* If user didn't specify the number of sectors, determine it now. */ - if (opts.num_sectors < 0) { - opts.num_sectors = ntfs_device_size_get(vol->u.dev, - opts.sector_size); - if (opts.num_sectors <= 0) { - ntfs_log_error("Couldn't determine the size of %s. " - "Please specify the number of sectors " - "manually.\n", vol->u.dev->d_name); - return FALSE; - } - } - ntfs_log_debug("number of sectors = %lld (0x%llx)\n", opts.num_sectors, - opts.num_sectors); - /* - * Reserve the last sector for the backup boot sector unless the - * sector size is less than 512 bytes in which case reserve 512 bytes - * worth of sectors. - */ - i = 1; - if (opts.sector_size < 512) - i = 512 / opts.sector_size; - opts.num_sectors -= i; - /* If user didn't specify the partition start sector, determine it. */ - if (opts.part_start_sect < 0) { - opts.part_start_sect = ntfs_device_partition_start_sector_get( - vol->u.dev); - if (opts.part_start_sect < 0) { - ntfs_log_warning("The partition start sector was not " - "specified for %s and it could not be obtained " - "automatically. It has been set to 0.\n", - vol->u.dev->d_name); - opts.part_start_sect = 0; - winboot = FALSE; - } else if (opts.part_start_sect >> 32) { - ntfs_log_warning("The partition start sector specified " - "for %s and the automatically determined value " - "is too large. It has been set to 0.\n", - vol->u.dev->d_name); - opts.part_start_sect = 0; - winboot = FALSE; - } - } else if (opts.part_start_sect >> 32) { - ntfs_log_error("Invalid partition start sector. Maximum is " - "4294967295 (2^32-1).\n"); - return FALSE; - } - /* If user didn't specify the sectors per track, determine it now. */ - if (opts.sectors_per_track < 0) { - opts.sectors_per_track = ntfs_device_sectors_per_track_get( - vol->u.dev); - if (opts.sectors_per_track < 0) { - ntfs_log_warning("The number of sectors per track was " - "not specified for %s and it could not be " - "obtained automatically. It has been set to " - "0.\n", vol->u.dev->d_name); - opts.sectors_per_track = 0; - winboot = FALSE; - } else if (opts.sectors_per_track > 65535) { - ntfs_log_warning("The number of sectors per track was " - "not specified for %s and the automatically " - "determined value is too large. It has been " - "set to 0.\n", vol->u.dev->d_name); - opts.sectors_per_track = 0; - winboot = FALSE; - } - } else if (opts.sectors_per_track > 65535) { - ntfs_log_error("Invalid number of sectors per track. Maximum " - "is 65535.\n"); - return FALSE; - } - /* If user didn't specify the number of heads, determine it now. */ - if (opts.heads < 0) { - opts.heads = ntfs_device_heads_get(vol->u.dev); - if (opts.heads < 0) { - ntfs_log_warning("The number of heads was not " - "specified for %s and it could not be obtained " - "automatically. It has been set to 0.\n", - vol->u.dev->d_name); - opts.heads = 0; - winboot = FALSE; - } else if (opts.heads > 65535) { - ntfs_log_warning("The number of heads was not " - "specified for %s and the automatically " - "determined value is too large. It has been " - "set to 0.\n", vol->u.dev->d_name); - opts.heads = 0; - winboot = FALSE; - } - } else if (opts.heads > 65535) { - ntfs_log_error("Invalid number of heads. Maximum is 65535.\n"); - return FALSE; - } - volume_size = opts.num_sectors * opts.sector_size; - /* Validate volume size. */ - if (volume_size < (1 << 20)) { /* 1MiB */ - ntfs_log_error("Device is too small (%llikiB). Minimum NTFS " - "volume size is 1MiB.\n", volume_size / 1024); - return FALSE; - } - ntfs_log_debug("volume size = %llikiB\n", volume_size / 1024); - /* If user didn't specify the cluster size, determine it now. */ - if (!vol->cluster_size) { - /* - * Windows Vista always uses 4096 bytes as the default cluster - * size regardless of the volume size so we do it, too. - */ - vol->cluster_size = 4096; - /* For small volumes on devices with large sector sizes. */ - if (vol->cluster_size < (u32)opts.sector_size) - vol->cluster_size = opts.sector_size; - /* - * For huge volumes, grow the cluster size until the number of - * clusters fits into 32 bits or the cluster size exceeds the - * maximum limit of 64kiB. - */ - while (volume_size >> (ffs(vol->cluster_size) - 1 + 32)) { - vol->cluster_size <<= 1; - if (vol->cluster_size > 65535) { - ntfs_log_error("Device is too large to hold an " - "NTFS volume (maximum size is " - "256TiB).\n"); - return FALSE; - } - } - ntfs_log_quiet("Cluster size has been automatically set to %u " - "bytes.\n", (unsigned)vol->cluster_size); - } - /* Validate cluster size. */ - if (vol->cluster_size & (vol->cluster_size - 1)) { - ntfs_log_error("The cluster size is invalid. It must be a " - "power of two, e.g. 1024, 4096.\n"); - return FALSE; - } - if (vol->cluster_size < (u32)opts.sector_size) { - ntfs_log_error("The cluster size is invalid. It must be equal " - "to, or larger than, the sector size.\n"); - return FALSE; - } - if (vol->cluster_size > 128 * (u32)opts.sector_size) { - ntfs_log_error("The cluster size is invalid. It cannot be " - "more that 128 times the size of the sector " - "size.\n"); - return FALSE; - } - if (vol->cluster_size > 65536) { - ntfs_log_error("The cluster size is invalid. The maximum " - "cluster size is 65536 bytes (64kiB).\n"); - return FALSE; - } - vol->cluster_size_bits = ffs(vol->cluster_size) - 1; - ntfs_log_debug("cluster size = %u bytes\n", - (unsigned int)vol->cluster_size); - if (vol->cluster_size > 4096) { - if (opts.enable_compression) { - if (!opts.force) { - ntfs_log_error("Windows cannot use compression " - "when the cluster size is " - "larger than 4096 bytes.\n"); - return FALSE; - } - opts.enable_compression = 0; - } - ntfs_log_warning("Windows cannot use compression when the " - "cluster size is larger than 4096 bytes. " - "Compression has been disabled for this " - "volume.\n"); - } - vol->nr_clusters = volume_size / vol->cluster_size; - /* - * Check the cluster_size and num_sectors for consistency with - * sector_size and num_sectors. And check both of these for consistency - * with volume_size. - */ - if ((vol->nr_clusters != ((opts.num_sectors * opts.sector_size) / - vol->cluster_size) || - (volume_size / opts.sector_size) != opts.num_sectors || - (volume_size / vol->cluster_size) != - vol->nr_clusters)) { - /* XXX is this code reachable? */ - ntfs_log_error("Illegal combination of volume/cluster/sector " - "size and/or cluster/sector number.\n"); - return FALSE; - } - ntfs_log_debug("number of clusters = %llu (0x%llx)\n", - vol->nr_clusters, vol->nr_clusters); - /* Number of clusters must fit within 32 bits (Win2k limitation). */ - if (vol->nr_clusters >> 32) { - if (vol->cluster_size >= 65536) { - ntfs_log_error("Device is too large to hold an NTFS " - "volume (maximum size is 256TiB).\n"); - return FALSE; - } - ntfs_log_error("Number of clusters exceeds 32 bits. Please " - "try again with a larger\ncluster size or " - "leave the cluster size unspecified and the " - "smallest possible cluster size for the size " - "of the device will be used.\n"); - return FALSE; - } - page_size = mkntfs_get_page_size(); - /* - * Set the mft record size. By default this is 1024 but it has to be - * at least as big as a sector and not bigger than a page on the system - * or the NTFS kernel driver will not be able to mount the volume. - * TODO: The mft record size should be user specifiable just like the - * "inode size" can be specified on other Linux/Unix file systems. - */ - vol->mft_record_size = 1024; - if (vol->mft_record_size < (u32)opts.sector_size) - vol->mft_record_size = opts.sector_size; - if (vol->mft_record_size > (unsigned long)page_size) - ntfs_log_warning("Mft record size (%u bytes) exceeds system " - "page size (%li bytes). You will not be able " - "to mount this volume using the NTFS kernel " - "driver.\n", (unsigned)vol->mft_record_size, - page_size); - vol->mft_record_size_bits = ffs(vol->mft_record_size) - 1; - ntfs_log_debug("mft record size = %u bytes\n", - (unsigned)vol->mft_record_size); - /* - * Set the index record size. By default this is 4096 but it has to be - * at least as big as a sector and not bigger than a page on the system - * or the NTFS kernel driver will not be able to mount the volume. - * FIXME: Should we make the index record size to be user specifiable? - */ - vol->indx_record_size = 4096; - if (vol->indx_record_size < (u32)opts.sector_size) - vol->indx_record_size = opts.sector_size; - if (vol->indx_record_size > (unsigned long)page_size) - ntfs_log_warning("Index record size (%u bytes) exceeds system " - "page size (%li bytes). You will not be able " - "to mount this volume using the NTFS kernel " - "driver.\n", (unsigned)vol->indx_record_size, - page_size); - vol->indx_record_size_bits = ffs(vol->indx_record_size) - 1; - ntfs_log_debug("index record size = %u bytes\n", - (unsigned)vol->indx_record_size); - if (!winboot) { - ntfs_log_warning("To boot from a device, Windows needs the " - "'partition start sector', the 'sectors per " - "track' and the 'number of heads' to be " - "set.\n"); - ntfs_log_warning("Windows will not be able to boot from this " - "device.\n"); - } - return TRUE; -} - -/** - * mkntfs_initialize_bitmaps - - */ -static BOOL mkntfs_initialize_bitmaps(void) -{ - u64 i; - int mft_bitmap_size; - - /* Determine lcn bitmap byte size and allocate it. */ - g_lcn_bitmap_byte_size = (g_vol->nr_clusters + 7) >> 3; - /* Needs to be multiple of 8 bytes. */ - g_lcn_bitmap_byte_size = (g_lcn_bitmap_byte_size + 7) & ~7; - i = (g_lcn_bitmap_byte_size + g_vol->cluster_size - 1) & - ~(g_vol->cluster_size - 1); - ntfs_log_debug("g_lcn_bitmap_byte_size = %i, allocated = %llu\n", - g_lcn_bitmap_byte_size, i); - g_lcn_bitmap = ntfs_calloc(g_lcn_bitmap_byte_size); - if (!g_lcn_bitmap) - return FALSE; - /* - * $Bitmap can overlap the end of the volume. Any bits in this region - * must be set. This region also encompasses the backup boot sector. - */ - for (i = g_vol->nr_clusters; i < (u64)g_lcn_bitmap_byte_size << 3; i++) - ntfs_bit_set(g_lcn_bitmap, i, 1); - /* - * Mft size is 27 (NTFS 3.0+) mft records or one cluster, whichever is - * bigger. - */ - g_mft_size = 27; - g_mft_size *= g_vol->mft_record_size; - if (g_mft_size < (s32)g_vol->cluster_size) - g_mft_size = g_vol->cluster_size; - ntfs_log_debug("MFT size = %i (0x%x) bytes\n", g_mft_size, g_mft_size); - /* Determine mft bitmap size and allocate it. */ - mft_bitmap_size = g_mft_size / g_vol->mft_record_size; - /* Convert to bytes, at least one. */ - g_mft_bitmap_byte_size = (mft_bitmap_size + 7) >> 3; - /* Mft bitmap is allocated in multiples of 8 bytes. */ - g_mft_bitmap_byte_size = (g_mft_bitmap_byte_size + 7) & ~7; - ntfs_log_debug("mft_bitmap_size = %i, g_mft_bitmap_byte_size = %i\n", - mft_bitmap_size, g_mft_bitmap_byte_size); - g_mft_bitmap = ntfs_calloc(g_mft_bitmap_byte_size); - if (!g_mft_bitmap) - return FALSE; - /* Create runlist for mft bitmap. */ - g_rl_mft_bmp = ntfs_malloc(2 * sizeof(runlist)); - if (!g_rl_mft_bmp) - return FALSE; - - g_rl_mft_bmp[0].vcn = 0LL; - /* Mft bitmap is right after $Boot's data. */ - i = (8192 + g_vol->cluster_size - 1) / g_vol->cluster_size; - g_rl_mft_bmp[0].lcn = i; - /* - * Size is always one cluster, even though valid data size and - * initialized data size are only 8 bytes. - */ - g_rl_mft_bmp[1].vcn = 1LL; - g_rl_mft_bmp[0].length = 1LL; - g_rl_mft_bmp[1].lcn = -1LL; - g_rl_mft_bmp[1].length = 0LL; - /* Allocate cluster for mft bitmap. */ - ntfs_bit_set(g_lcn_bitmap, i, 1); - return TRUE; -} - -/** - * mkntfs_initialize_rl_mft - - */ -static BOOL mkntfs_initialize_rl_mft(void) -{ - int i, j; - - /* If user didn't specify the mft lcn, determine it now. */ - if (!g_mft_lcn) { - /* - * We start at the higher value out of 16kiB and just after the - * mft bitmap. - */ - g_mft_lcn = g_rl_mft_bmp[0].lcn + g_rl_mft_bmp[0].length; - if (g_mft_lcn * g_vol->cluster_size < 16 * 1024) - g_mft_lcn = (16 * 1024 + g_vol->cluster_size - 1) / - g_vol->cluster_size; - } - ntfs_log_debug("$MFT logical cluster number = 0x%llx\n", g_mft_lcn); - /* Determine MFT zone size. */ - g_mft_zone_end = g_vol->nr_clusters; - switch (opts.mft_zone_multiplier) { /* % of volume size in clusters */ - case 4: - g_mft_zone_end = g_mft_zone_end >> 1; /* 50% */ - break; - case 3: - g_mft_zone_end = g_mft_zone_end * 3 >> 3;/* 37.5% */ - break; - case 2: - g_mft_zone_end = g_mft_zone_end >> 2; /* 25% */ - break; - case 1: - default: - g_mft_zone_end = g_mft_zone_end >> 3; /* 12.5% */ - break; - } - ntfs_log_debug("MFT zone size = %lldkiB\n", g_mft_zone_end << - g_vol->cluster_size_bits >> 10 /* >> 10 == / 1024 */); - /* - * The mft zone begins with the mft data attribute, not at the beginning - * of the device. - */ - g_mft_zone_end += g_mft_lcn; - /* Create runlist for mft. */ - g_rl_mft = ntfs_malloc(2 * sizeof(runlist)); - if (!g_rl_mft) - return FALSE; - - g_rl_mft[0].vcn = 0LL; - g_rl_mft[0].lcn = g_mft_lcn; - /* rounded up division by cluster size */ - j = (g_mft_size + g_vol->cluster_size - 1) / g_vol->cluster_size; - g_rl_mft[1].vcn = j; - g_rl_mft[0].length = j; - g_rl_mft[1].lcn = -1LL; - g_rl_mft[1].length = 0LL; - /* Allocate clusters for mft. */ - for (i = 0; i < j; i++) - ntfs_bit_set(g_lcn_bitmap, g_mft_lcn + i, 1); - /* Determine mftmirr_lcn (middle of volume). */ - g_mftmirr_lcn = (opts.num_sectors * opts.sector_size >> 1) - / g_vol->cluster_size; - ntfs_log_debug("$MFTMirr logical cluster number = 0x%llx\n", - g_mftmirr_lcn); - /* Create runlist for mft mirror. */ - g_rl_mftmirr = ntfs_malloc(2 * sizeof(runlist)); - if (!g_rl_mftmirr) - return FALSE; - - g_rl_mftmirr[0].vcn = 0LL; - g_rl_mftmirr[0].lcn = g_mftmirr_lcn; - /* - * The mft mirror is either 4kb (the first four records) or one cluster - * in size, which ever is bigger. In either case, it contains a - * byte-for-byte identical copy of the beginning of the mft (i.e. either - * the first four records (4kb) or the first cluster worth of records, - * whichever is bigger). - */ - j = (4 * g_vol->mft_record_size + g_vol->cluster_size - 1) / g_vol->cluster_size; - g_rl_mftmirr[1].vcn = j; - g_rl_mftmirr[0].length = j; - g_rl_mftmirr[1].lcn = -1LL; - g_rl_mftmirr[1].length = 0LL; - /* Allocate clusters for mft mirror. */ - for (i = 0; i < j; i++) - ntfs_bit_set(g_lcn_bitmap, g_mftmirr_lcn + i, 1); - g_logfile_lcn = g_mftmirr_lcn + j; - ntfs_log_debug("$LogFile logical cluster number = 0x%llx\n", - g_logfile_lcn); - return TRUE; -} - -/** - * mkntfs_initialize_rl_logfile - - */ -static BOOL mkntfs_initialize_rl_logfile(void) -{ - int i, j; - u64 volume_size; - - /* Create runlist for log file. */ - g_rl_logfile = ntfs_malloc(2 * sizeof(runlist)); - if (!g_rl_logfile) - return FALSE; - - - volume_size = g_vol->nr_clusters << g_vol->cluster_size_bits; - - g_rl_logfile[0].vcn = 0LL; - g_rl_logfile[0].lcn = g_logfile_lcn; - /* - * Determine logfile_size from volume_size (rounded up to a cluster), - * making sure it does not overflow the end of the volume. - */ - if (volume_size < 2048LL * 1024) /* < 2MiB */ - g_logfile_size = 256LL * 1024; /* -> 256kiB */ - else if (volume_size < 4000000LL) /* < 4MB */ - g_logfile_size = 512LL * 1024; /* -> 512kiB */ - else if (volume_size <= 200LL * 1024 * 1024) /* < 200MiB */ - g_logfile_size = 2048LL * 1024; /* -> 2MiB */ - else { - /* - * FIXME: The $LogFile size is 64 MiB upwards from 12GiB but - * the "200" divider below apparently approximates "100" or - * some other value as the volume size decreases. For example: - * Volume size LogFile size Ratio - * 8799808 46048 191.100 - * 8603248 45072 190.877 - * 7341704 38768 189.375 - * 6144828 32784 187.433 - * 4192932 23024 182.111 - */ - if (volume_size >= 12LL << 30) /* > 12GiB */ - g_logfile_size = 64 << 20; /* -> 64MiB */ - else - g_logfile_size = (volume_size / 200) & - ~(g_vol->cluster_size - 1); - } - j = g_logfile_size / g_vol->cluster_size; - while (g_rl_logfile[0].lcn + j >= g_vol->nr_clusters) { - /* - * $Logfile would overflow volume. Need to make it smaller than - * the standard size. It's ok as we are creating a non-standard - * volume anyway if it is that small. - */ - g_logfile_size >>= 1; - j = g_logfile_size / g_vol->cluster_size; - } - g_logfile_size = (g_logfile_size + g_vol->cluster_size - 1) & - ~(g_vol->cluster_size - 1); - ntfs_log_debug("$LogFile (journal) size = %ikiB\n", - g_logfile_size / 1024); - /* - * FIXME: The 256kiB limit is arbitrary. Should find out what the real - * minimum requirement for Windows is so it doesn't blue screen. - */ - if (g_logfile_size < 256 << 10) { - ntfs_log_error("$LogFile would be created with invalid size. " - "This is not allowed as it would cause Windows " - "to blue screen and during boot.\n"); - return FALSE; - } - g_rl_logfile[1].vcn = j; - g_rl_logfile[0].length = j; - g_rl_logfile[1].lcn = -1LL; - g_rl_logfile[1].length = 0LL; - /* Allocate clusters for log file. */ - for (i = 0; i < j; i++) - ntfs_bit_set(g_lcn_bitmap, g_logfile_lcn + i, 1); - return TRUE; -} - -/** - * mkntfs_initialize_rl_boot - - */ -static BOOL mkntfs_initialize_rl_boot(void) -{ - int i, j; - /* Create runlist for $Boot. */ - g_rl_boot = ntfs_malloc(2 * sizeof(runlist)); - if (!g_rl_boot) - return FALSE; - - g_rl_boot[0].vcn = 0LL; - g_rl_boot[0].lcn = 0LL; - /* - * $Boot is always 8192 (0x2000) bytes or 1 cluster, whichever is - * bigger. - */ - j = (8192 + g_vol->cluster_size - 1) / g_vol->cluster_size; - g_rl_boot[1].vcn = j; - g_rl_boot[0].length = j; - g_rl_boot[1].lcn = -1LL; - g_rl_boot[1].length = 0LL; - /* Allocate clusters for $Boot. */ - for (i = 0; i < j; i++) - ntfs_bit_set(g_lcn_bitmap, 0LL + i, 1); - return TRUE; -} - -/** - * mkntfs_initialize_rl_bad - - */ -static BOOL mkntfs_initialize_rl_bad(void) -{ - /* Create runlist for $BadClus, $DATA named stream $Bad. */ - g_rl_bad = ntfs_malloc(2 * sizeof(runlist)); - if (!g_rl_bad) - return FALSE; - - g_rl_bad[0].vcn = 0LL; - g_rl_bad[0].lcn = -1LL; - /* - * $BadClus named stream $Bad contains the whole volume as a single - * sparse runlist entry. - */ - g_rl_bad[1].vcn = g_vol->nr_clusters; - g_rl_bad[0].length = g_vol->nr_clusters; - g_rl_bad[1].lcn = -1LL; - g_rl_bad[1].length = 0LL; - - /* TODO: Mark bad blocks as such. */ - return TRUE; -} - -/** - * mkntfs_fill_device_with_zeroes - - */ -static BOOL mkntfs_fill_device_with_zeroes(void) -{ - /* - * If not quick format, fill the device with 0s. - * FIXME: Except bad blocks! (AIA) - */ - int i; - ssize_t bw; - unsigned long long position; - float progress_inc = (float)g_vol->nr_clusters / 100; - u64 volume_size; - - volume_size = g_vol->nr_clusters << g_vol->cluster_size_bits; - - ntfs_log_progress("Initializing device with zeroes: 0%%"); - for (position = 0; position < (unsigned long long)g_vol->nr_clusters; - position++) { - if (!(position % (int)(progress_inc+1))) { - ntfs_log_progress("\b\b\b\b%3.0f%%", position / - progress_inc); - } - bw = mkntfs_write(g_vol->u.dev, g_buf, g_vol->cluster_size); - if (bw != (ssize_t)g_vol->cluster_size) { - if (bw != -1 || errno != EIO) { - ntfs_log_error("This should not happen.\n"); - return FALSE; - } - if (!position) { - ntfs_log_error("Error: Cluster zero is bad. " - "Cannot create NTFS file " - "system.\n"); - return FALSE; - } - /* Add the baddie to our bad blocks list. */ - if (!append_to_bad_blocks(position)) - return FALSE; - ntfs_log_quiet("\nFound bad cluster (%lld). Adding to " - "list of bad blocks.\nInitializing " - "device with zeroes: %3.0f%%", position, - position / progress_inc); - /* Seek to next cluster. */ - g_vol->u.dev->d_ops->seek(g_vol->u.dev, - ((off_t)position + 1) * - g_vol->cluster_size, SEEK_SET); - } - } - ntfs_log_progress("\b\b\b\b100%%"); - position = (volume_size & (g_vol->cluster_size - 1)) / - opts.sector_size; - for (i = 0; (unsigned long)i < position; i++) { - bw = mkntfs_write(g_vol->u.dev, g_buf, opts.sector_size); - if (bw != opts.sector_size) { - if (bw != -1 || errno != EIO) { - ntfs_log_error("This should not happen.\n"); - return FALSE; - } else if (i + 1ull == position) { - ntfs_log_error("Error: Bad cluster found in " - "location reserved for system " - "file $Boot.\n"); - return FALSE; - } - /* Seek to next sector. */ - g_vol->u.dev->d_ops->seek(g_vol->u.dev, - opts.sector_size, SEEK_CUR); - } - } - ntfs_log_progress(" - Done.\n"); - return TRUE; -} - -/** - * mkntfs_sync_index_record - * - * (ERSO) made a function out of this, but the reason for doing that - * disappeared during coding.... - */ -static BOOL mkntfs_sync_index_record(INDEX_ALLOCATION* idx, MFT_RECORD* m, - ntfschar* name, u32 name_len) -{ - int i, err; - ntfs_attr_search_ctx *ctx; - ATTR_RECORD *a; - long long lw; - runlist *rl_index = NULL; - - i = 5 * sizeof(ntfschar); - ctx = ntfs_attr_get_search_ctx(NULL, m); - if (!ctx) { - ntfs_log_perror("Failed to allocate attribute search context"); - return FALSE; - } - /* FIXME: This should be IGNORE_CASE! */ - if (mkntfs_attr_lookup(AT_INDEX_ALLOCATION, name, name_len, 0, 0, - NULL, 0, ctx)) { - ntfs_attr_put_search_ctx(ctx); - ntfs_log_error("BUG: $INDEX_ALLOCATION attribute not found.\n"); - return FALSE; - } - a = ctx->attr; - rl_index = ntfs_mapping_pairs_decompress(g_vol, a, NULL); - if (!rl_index) { - ntfs_attr_put_search_ctx(ctx); - ntfs_log_error("Failed to decompress runlist of $INDEX_ALLOCATION " - "attribute.\n"); - return FALSE; - } - if (sle64_to_cpu(a->u.nonres.initialized_size) < i) { - ntfs_attr_put_search_ctx(ctx); - free(rl_index); - ntfs_log_error("BUG: $INDEX_ALLOCATION attribute too short.\n"); - return FALSE; - } - ntfs_attr_put_search_ctx(ctx); - i = sizeof(INDEX_BLOCK) - sizeof(INDEX_HEADER) + - le32_to_cpu(idx->index.allocated_size); - err = ntfs_mst_pre_write_fixup((NTFS_RECORD*)idx, i); - if (err) { - free(rl_index); - ntfs_log_error("ntfs_mst_pre_write_fixup() failed while " - "syncing index block.\n"); - return FALSE; - } - lw = ntfs_rlwrite(g_vol->u.dev, rl_index, (u8*)idx, i, NULL); - free(rl_index); - if (lw != i) { - ntfs_log_error("Error writing $INDEX_ALLOCATION.\n"); - return FALSE; - } - /* No more changes to @idx below here so no need for fixup: */ - /* ntfs_mst_post_write_fixup((NTFS_RECORD*)idx); */ - return TRUE; -} - -/** - * create_file_volume - - */ -static BOOL create_file_volume(MFT_RECORD *m, leMFT_REF root_ref, - VOLUME_FLAGS fl, const GUID *volume_guid -#ifndef ENABLE_UUID - __attribute__((unused)) -#endif - ) -{ - int i, err; - u8 *sd; - - ntfs_log_verbose("Creating $Volume (mft record 3)\n"); - m = (MFT_RECORD*)(g_buf + 3 * g_vol->mft_record_size); - err = create_hardlink(g_index_block, root_ref, m, - MK_LE_MREF(FILE_Volume, FILE_Volume), 0LL, 0LL, - FILE_ATTR_HIDDEN | FILE_ATTR_SYSTEM, 0, 0, - "$Volume", FILE_NAME_WIN32_AND_DOS); - if (!err) { - init_system_file_sd(FILE_Volume, &sd, &i); - err = add_attr_sd(m, sd, i); - } - if (!err) - err = add_attr_data(m, NULL, 0, 0, 0, NULL, 0); - if (!err) - err = add_attr_vol_name(m, g_vol->vol_name, g_vol->vol_name ? - strlen(g_vol->vol_name) : 0); - if (!err) { - if (fl & VOLUME_IS_DIRTY) - ntfs_log_quiet("Setting the volume dirty so check " - "disk runs on next reboot into " - "Windows.\n"); - err = add_attr_vol_info(m, fl, g_vol->major_ver, - g_vol->minor_ver); - } -#ifdef ENABLE_UUID - if (!err) - err = add_attr_object_id(m, volume_guid); -#endif - if (err < 0) { - ntfs_log_error("Couldn't create $Volume: %s\n", - strerror(-err)); - return FALSE; - } - return TRUE; -} - -/** - * create_backup_boot_sector - * - * Return 0 on success or -1 if it couldn't be created. - */ -static int create_backup_boot_sector(u8 *buff) -{ - const char *s; - ssize_t bw; - int size, e; - - ntfs_log_verbose("Creating backup boot sector.\n"); - /* - * Write the first max(512, opts.sector_size) bytes from buf to the - * last sector, but limit that to 8192 bytes of written data since that - * is how big $Boot is (and how big our buffer is).. - */ - size = 512; - if (size < opts.sector_size) - size = opts.sector_size; - if (size < opts.cluster_size) - size = opts.cluster_size; - if (g_vol->u.dev->d_ops->seek(g_vol->u.dev, (opts.num_sectors + 1) * - opts.sector_size - size, SEEK_SET) == (off_t)-1) { - ntfs_log_perror("Seek failed"); - goto bb_err; - } - if (size > 8192) - size = 8192; - bw = mkntfs_write(g_vol->u.dev, buff, size); - if (bw == size) - return 0; - e = errno; - if (bw == -1LL) - s = strerror(e); - else - s = "unknown error"; - /* At least some 2.4 kernels return EIO instead of ENOSPC. */ - if (bw != -1LL || (bw == -1LL && e != ENOSPC && e != EIO)) { - ntfs_log_critical("Couldn't write backup boot sector: %s\n", s); - return -1; - } -bb_err: - ntfs_log_error("Couldn't write backup boot sector. This is due to a " - "limitation in the\nLinux kernel. This is not a major " - "problem as Windows check disk will create the\n" - "backup boot sector when it is run on your next boot " - "into Windows.\n"); - return -1; -} - -/** - * mkntfs_create_root_structures - - */ -static BOOL mkntfs_create_root_structures(void) -{ - NTFS_BOOT_SECTOR *bs; - MFT_RECORD *m; - leMFT_REF root_ref; - leMFT_REF extend_ref; - int i; - int j; - int err; - u8 *sd; - FILE_ATTR_FLAGS extend_flags; - VOLUME_FLAGS volume_flags = 0; - int nr_sysfiles; - u8 *buf_log = NULL; - int buf_sds_first_size; - char *buf_sds; - - ntfs_log_quiet("Creating NTFS volume structures.\n"); - nr_sysfiles = 27; - /* - * Setup an empty mft record. Note, we can just give 0 as the mft - * reference as we are creating an NTFS 1.2 volume for which the mft - * reference is ignored by ntfs_mft_record_layout(). - * - * Copy the mft record onto all 16 records in the buffer and setup the - * sequence numbers of each system file to equal the mft record number - * of that file (only for $MFT is the sequence number 1 rather than 0). - */ - for (i = 0; i < nr_sysfiles; i++) { - if (ntfs_mft_record_layout(g_vol, 0, m = (MFT_RECORD *)(g_buf + - i * g_vol->mft_record_size))) { - ntfs_log_error("Failed to layout system mft records." - "\n"); - return FALSE; - } - if (i == 0 || i > 23) - m->sequence_number = cpu_to_le16(1); - else - m->sequence_number = cpu_to_le16(i); - } - /* - * If only one cluster contains all system files then - * fill the rest of it with empty, formatted records. - */ - if (nr_sysfiles * (s32)g_vol->mft_record_size < g_mft_size) { - for (i = nr_sysfiles; - i * (s32)g_vol->mft_record_size < g_mft_size; i++) { - m = (MFT_RECORD *)(g_buf + i * g_vol->mft_record_size); - if (ntfs_mft_record_layout(g_vol, 0, m)) { - ntfs_log_error("Failed to layout mft record." - "\n"); - return FALSE; - } - m->flags = cpu_to_le16(0); - m->sequence_number = cpu_to_le16(i); - } - } - /* - * Create the 16 system files, adding the system information attribute - * to each as well as marking them in use in the mft bitmap. - */ - for (i = 0; i < nr_sysfiles; i++) { - le32 file_attrs; - - m = (MFT_RECORD*)(g_buf + i * g_vol->mft_record_size); - if (i < 16 || i > 23) { - m->mft_record_number = cpu_to_le32(i); - m->flags |= MFT_RECORD_IN_USE; - ntfs_bit_set(g_mft_bitmap, 0LL + i, 1); - } - file_attrs = FILE_ATTR_HIDDEN | FILE_ATTR_SYSTEM; - if (i == FILE_root) { - file_attrs |= FILE_ATTR_ARCHIVE; - if (opts.disable_indexing) - file_attrs |= FILE_ATTR_NOT_CONTENT_INDEXED; - if (opts.enable_compression) - file_attrs |= FILE_ATTR_COMPRESSED; - } - /* setting specific security_id flag and */ - /* file permissions for ntfs 3.x */ - if (i == 0 || i == 1 || i == 2 || i == 6 || i == 8 || - i == 10) { - add_attr_std_info(m, file_attrs, - cpu_to_le32(0x0100)); - } else if (i == 9) { - file_attrs |= FILE_ATTR_VIEW_INDEX_PRESENT; - add_attr_std_info(m, file_attrs, - cpu_to_le32(0x0101)); - } else if (i == 11) { - add_attr_std_info(m, file_attrs, - cpu_to_le32(0x0101)); - } else if (i == 24 || i == 25 || i == 26) { - file_attrs |= FILE_ATTR_ARCHIVE; - file_attrs |= FILE_ATTR_VIEW_INDEX_PRESENT; - add_attr_std_info(m, file_attrs, - cpu_to_le32(0x0101)); - } else { - add_attr_std_info(m, file_attrs, - cpu_to_le32(0x00)); - } - } - /* The root directory mft reference. */ - root_ref = MK_LE_MREF(FILE_root, FILE_root); - extend_ref = MK_LE_MREF(11,11); - ntfs_log_verbose("Creating root directory (mft record 5)\n"); - m = (MFT_RECORD*)(g_buf + 5 * g_vol->mft_record_size); - m->flags |= MFT_RECORD_IS_DIRECTORY; - m->link_count = cpu_to_le16(le16_to_cpu(m->link_count) + 1); - err = add_attr_file_name(m, root_ref, 0LL, 0LL, - FILE_ATTR_HIDDEN | FILE_ATTR_SYSTEM | - FILE_ATTR_I30_INDEX_PRESENT, 0, 0, ".", - FILE_NAME_WIN32_AND_DOS); - if (!err) { - init_root_sd(&sd, &i); - err = add_attr_sd(m, sd, i); - } - /* FIXME: This should be IGNORE_CASE */ - if (!err) - err = add_attr_index_root(m, "$I30", 4, 0, AT_FILE_NAME, - COLLATION_FILE_NAME, g_vol->indx_record_size); - /* FIXME: This should be IGNORE_CASE */ - if (!err) - err = upgrade_to_large_index(m, "$I30", 4, 0, &g_index_block); - if (!err) { - ntfs_attr_search_ctx *ctx; - ATTR_RECORD *a; - ctx = ntfs_attr_get_search_ctx(NULL, m); - if (!ctx) { - ntfs_log_perror("Failed to allocate attribute search " - "context"); - return FALSE; - } - /* There is exactly one file name so this is ok. */ - if (mkntfs_attr_lookup(AT_FILE_NAME, AT_UNNAMED, 0, 0, 0, NULL, - 0, ctx)) { - ntfs_attr_put_search_ctx(ctx); - ntfs_log_error("BUG: $FILE_NAME attribute not found." - "\n"); - return FALSE; - } - a = ctx->attr; - err = insert_file_link_in_dir_index(g_index_block, root_ref, - (FILE_NAME_ATTR*)((char*)a + - le16_to_cpu(a->u.res.value_offset)), - le32_to_cpu(a->u.res.value_length)); - ntfs_attr_put_search_ctx(ctx); - } - if (err) { - ntfs_log_error("Couldn't create root directory: %s\n", - strerror(-err)); - return FALSE; - } - /* Add all other attributes, on a per-file basis for clarity. */ - ntfs_log_verbose("Creating $MFT (mft record 0)\n"); - m = (MFT_RECORD*)g_buf; - err = add_attr_data_positioned(m, NULL, 0, 0, 0, g_rl_mft, g_buf, - g_mft_size); - if (!err) - err = create_hardlink(g_index_block, root_ref, m, - MK_LE_MREF(FILE_MFT, 1), g_mft_size, - g_mft_size, FILE_ATTR_HIDDEN | - FILE_ATTR_SYSTEM, 0, 0, "$MFT", - FILE_NAME_WIN32_AND_DOS); - /* mft_bitmap is not modified in mkntfs; no need to sync it later. */ - if (!err) - err = add_attr_bitmap_positioned(m, NULL, 0, 0, g_rl_mft_bmp, - g_mft_bitmap, g_mft_bitmap_byte_size); - if (err < 0) { - ntfs_log_error("Couldn't create $MFT: %s\n", strerror(-err)); - return FALSE; - } - ntfs_log_verbose("Creating $MFTMirr (mft record 1)\n"); - m = (MFT_RECORD*)(g_buf + 1 * g_vol->mft_record_size); - err = add_attr_data_positioned(m, NULL, 0, 0, 0, g_rl_mftmirr, g_buf, - g_rl_mftmirr[0].length * g_vol->cluster_size); - if (!err) - err = create_hardlink(g_index_block, root_ref, m, - MK_LE_MREF(FILE_MFTMirr, FILE_MFTMirr), - g_rl_mftmirr[0].length * g_vol->cluster_size, - g_rl_mftmirr[0].length * g_vol->cluster_size, - FILE_ATTR_HIDDEN | FILE_ATTR_SYSTEM, 0, 0, - "$MFTMirr", FILE_NAME_WIN32_AND_DOS); - if (err < 0) { - ntfs_log_error("Couldn't create $MFTMirr: %s\n", - strerror(-err)); - return FALSE; - } - ntfs_log_verbose("Creating $LogFile (mft record 2)\n"); - m = (MFT_RECORD*)(g_buf + 2 * g_vol->mft_record_size); - buf_log = ntfs_malloc(g_logfile_size); - if (!buf_log) - return FALSE; - memset(buf_log, -1, g_logfile_size); - err = add_attr_data_positioned(m, NULL, 0, 0, 0, g_rl_logfile, buf_log, - g_logfile_size); - free(buf_log); - buf_log = NULL; - if (!err) - err = create_hardlink(g_index_block, root_ref, m, - MK_LE_MREF(FILE_LogFile, FILE_LogFile), - g_logfile_size, g_logfile_size, - FILE_ATTR_HIDDEN | FILE_ATTR_SYSTEM, 0, 0, - "$LogFile", FILE_NAME_WIN32_AND_DOS); - if (err < 0) { - ntfs_log_error("Couldn't create $LogFile: %s\n", - strerror(-err)); - return FALSE; - } - ntfs_log_verbose("Creating $AttrDef (mft record 4)\n"); - m = (MFT_RECORD*)(g_buf + 4 * g_vol->mft_record_size); - err = add_attr_data(m, NULL, 0, 0, 0, (u8*)g_vol->attrdef, - g_vol->attrdef_len); - if (!err) - err = create_hardlink(g_index_block, root_ref, m, - MK_LE_MREF(FILE_AttrDef, FILE_AttrDef), - (g_vol->attrdef_len + g_vol->cluster_size - 1) & - ~(g_vol->cluster_size - 1), g_vol->attrdef_len, - FILE_ATTR_HIDDEN | FILE_ATTR_SYSTEM, 0, 0, - "$AttrDef", FILE_NAME_WIN32_AND_DOS); - if (!err) { - init_system_file_sd(FILE_AttrDef, &sd, &i); - err = add_attr_sd(m, sd, i); - } - if (err < 0) { - ntfs_log_error("Couldn't create $AttrDef: %s\n", - strerror(-err)); - return FALSE; - } - ntfs_log_verbose("Creating $Bitmap (mft record 6)\n"); - m = (MFT_RECORD*)(g_buf + 6 * g_vol->mft_record_size); - /* the data attribute of $Bitmap must be non-resident or otherwise */ - /* windows 2003 will regard the volume as corrupt (ERSO) */ - if (!err) - err = insert_non_resident_attr_in_mft_record(m, - AT_DATA, NULL, 0, 0, 0, - g_lcn_bitmap, g_lcn_bitmap_byte_size); - - - if (!err) - err = create_hardlink(g_index_block, root_ref, m, - MK_LE_MREF(FILE_Bitmap, FILE_Bitmap), - (g_lcn_bitmap_byte_size + g_vol->cluster_size - - 1) & ~(g_vol->cluster_size - 1), - g_lcn_bitmap_byte_size, - FILE_ATTR_HIDDEN | FILE_ATTR_SYSTEM, 0, 0, - "$Bitmap", FILE_NAME_WIN32_AND_DOS); - if (err < 0) { - ntfs_log_error("Couldn't create $Bitmap: %s\n", strerror(-err)); - return FALSE; - } - ntfs_log_verbose("Creating $Boot (mft record 7)\n"); - m = (MFT_RECORD*)(g_buf + 7 * g_vol->mft_record_size); - bs = ntfs_calloc(8192); - if (!bs) - return FALSE; - memcpy(bs, boot_array, sizeof(boot_array)); - /* - * Create the boot sector in bs. Note, that bs is already zeroed - * in the boot sector section and that it has the NTFS OEM id/magic - * already inserted, so no need to worry about these things. - */ - bs->bpb.bytes_per_sector = cpu_to_le16(opts.sector_size); - bs->bpb.sectors_per_cluster = (u8)(g_vol->cluster_size / - opts.sector_size); - bs->bpb.media_type = 0xf8; /* hard disk */ - bs->bpb.sectors_per_track = cpu_to_le16(opts.sectors_per_track); - ntfs_log_debug("sectors per track = %ld (0x%lx)\n", - opts.sectors_per_track, opts.sectors_per_track); - bs->bpb.heads = cpu_to_le16(opts.heads); - ntfs_log_debug("heads = %ld (0x%lx)\n", opts.heads, opts.heads); - bs->bpb.hidden_sectors = cpu_to_le32(opts.part_start_sect); - ntfs_log_debug("hidden sectors = %llu (0x%llx)\n", opts.part_start_sect, - opts.part_start_sect); - bs->physical_drive = 0x80; /* boot from hard disk */ - bs->extended_boot_signature = 0x80; /* everybody sets this, so we do */ - bs->number_of_sectors = cpu_to_sle64(opts.num_sectors); - bs->mft_lcn = cpu_to_sle64(g_mft_lcn); - bs->mftmirr_lcn = cpu_to_sle64(g_mftmirr_lcn); - if (g_vol->mft_record_size >= g_vol->cluster_size) { - bs->clusters_per_mft_record = g_vol->mft_record_size / - g_vol->cluster_size; - } else { - bs->clusters_per_mft_record = -(ffs(g_vol->mft_record_size) - - 1); - if ((u32)(1 << -bs->clusters_per_mft_record) != - g_vol->mft_record_size) { - free(bs); - ntfs_log_error("BUG: calculated clusters_per_mft_record" - " is wrong (= 0x%x)\n", - bs->clusters_per_mft_record); - return FALSE; - } - } - ntfs_log_debug("clusters per mft record = %i (0x%x)\n", - bs->clusters_per_mft_record, - bs->clusters_per_mft_record); - if (g_vol->indx_record_size >= g_vol->cluster_size) { - bs->clusters_per_index_record = g_vol->indx_record_size / - g_vol->cluster_size; - } else { - bs->clusters_per_index_record = -g_vol->indx_record_size_bits; - if ((1 << -bs->clusters_per_index_record) != - (s32)g_vol->indx_record_size) { - free(bs); - ntfs_log_error("BUG: calculated " - "clusters_per_index_record is wrong " - "(= 0x%x)\n", - bs->clusters_per_index_record); - return FALSE; - } - } - ntfs_log_debug("clusters per index block = %i (0x%x)\n", - bs->clusters_per_index_record, - bs->clusters_per_index_record); - /* Generate a 64-bit random number for the serial number. */ - bs->volume_serial_number = cpu_to_le64(((u64)random() << 32) | - ((u64)random() & 0xffffffff)); - /* - * Leave zero for now as NT4 leaves it zero, too. If want it later, see - * ../libntfs/bootsect.c for how to calculate it. - */ - bs->checksum = cpu_to_le32(0); - /* Make sure the bootsector is ok. */ - if (!ntfs_boot_sector_is_ntfs(bs, TRUE)) { - free(bs); - ntfs_log_error("FATAL: Generated boot sector is invalid!\n"); - return FALSE; - } - err = add_attr_data_positioned(m, NULL, 0, 0, 0, g_rl_boot, (u8*)bs, - 8192); - if (!err) - err = create_hardlink(g_index_block, root_ref, m, - MK_LE_MREF(FILE_Boot, FILE_Boot), - (8192 + g_vol->cluster_size - 1) & - ~(g_vol->cluster_size - 1), 8192, - FILE_ATTR_HIDDEN | FILE_ATTR_SYSTEM, 0, 0, - "$Boot", FILE_NAME_WIN32_AND_DOS); - if (!err) { - init_system_file_sd(FILE_Boot, &sd, &i); - err = add_attr_sd(m, sd, i); - } - if (err < 0) { - free(bs); - ntfs_log_error("Couldn't create $Boot: %s\n", strerror(-err)); - return FALSE; - } - if (create_backup_boot_sector((u8*)bs)) { - /* - * Pre-2.6 kernels couldn't access the last sector if it was - * odd and we failed to set the device block size to the sector - * size, hence we schedule chkdsk to create it. - */ - volume_flags |= VOLUME_IS_DIRTY; - } - free(bs); -#ifdef ENABLE_UUID - /* - * We cheat a little here and if the user has requested all times to be - * set to zero then we set the GUID to zero as well. This options is - * only used for development purposes so that should be fine. - */ - if (!opts.use_epoch_time) { - /* Generate a GUID for the volume. */ - uuid_generate((void*)&g_vol->guid); - } else - memset(&g_vol->guid, 0, sizeof(g_vol->guid)); -#endif - if (!create_file_volume(m, root_ref, volume_flags, &g_vol->guid)) - return FALSE; - ntfs_log_verbose("Creating $BadClus (mft record 8)\n"); - m = (MFT_RECORD*)(g_buf + 8 * g_vol->mft_record_size); - /* FIXME: This should be IGNORE_CASE */ - /* Create a sparse named stream of size equal to the volume size. */ - err = add_attr_data_positioned(m, "$Bad", 4, 0, 0, g_rl_bad, NULL, - g_vol->nr_clusters * g_vol->cluster_size); - if (!err) { - err = add_attr_data(m, NULL, 0, 0, 0, NULL, 0); - } - if (!err) { - err = create_hardlink(g_index_block, root_ref, m, - MK_LE_MREF(FILE_BadClus, FILE_BadClus), - 0LL, 0LL, FILE_ATTR_HIDDEN | FILE_ATTR_SYSTEM, - 0, 0, "$BadClus", FILE_NAME_WIN32_AND_DOS); - } - if (err < 0) { - ntfs_log_error("Couldn't create $BadClus: %s\n", - strerror(-err)); - return FALSE; - } - /* create $Secure (NTFS 3.0+) */ - ntfs_log_verbose("Creating $Secure (mft record 9)\n"); - m = (MFT_RECORD*)(g_buf + 9 * g_vol->mft_record_size); - m->flags |= MFT_RECORD_IS_VIEW_INDEX; - if (!err) - err = create_hardlink(g_index_block, root_ref, m, - MK_LE_MREF(9, 9), 0LL, 0LL, - FILE_ATTR_HIDDEN | FILE_ATTR_SYSTEM | - FILE_ATTR_VIEW_INDEX_PRESENT, 0, 0, - "$Secure", FILE_NAME_WIN32_AND_DOS); - buf_sds = NULL; - buf_sds_first_size = 0; - if (!err) { - int buf_sds_size; - - buf_sds_first_size = 0xfc; - buf_sds_size = 0x40000 + buf_sds_first_size; - buf_sds = ntfs_calloc(buf_sds_size); - if (!buf_sds) - return FALSE; - init_secure_sds(buf_sds); - memcpy(buf_sds + 0x40000, buf_sds, buf_sds_first_size); - err = add_attr_data(m, "$SDS", 4, 0, 0, (u8*)buf_sds, - buf_sds_size); - } - /* FIXME: This should be IGNORE_CASE */ - if (!err) - err = add_attr_index_root(m, "$SDH", 4, 0, AT_UNUSED, - COLLATION_NTOFS_SECURITY_HASH, - g_vol->indx_record_size); - /* FIXME: This should be IGNORE_CASE */ - if (!err) - err = add_attr_index_root(m, "$SII", 4, 0, AT_UNUSED, - COLLATION_NTOFS_ULONG, g_vol->indx_record_size); - if (!err) - err = initialize_secure(buf_sds, buf_sds_first_size, m); - free(buf_sds); - if (err < 0) { - ntfs_log_error("Couldn't create $Secure: %s\n", - strerror(-err)); - return FALSE; - } - ntfs_log_verbose("Creating $UpCase (mft record 0xa)\n"); - m = (MFT_RECORD*)(g_buf + 0xa * g_vol->mft_record_size); - err = add_attr_data(m, NULL, 0, 0, 0, (u8*)g_vol->upcase, - g_vol->upcase_len << 1); - if (!err) - err = create_hardlink(g_index_block, root_ref, m, - MK_LE_MREF(FILE_UpCase, FILE_UpCase), - ((g_vol->upcase_len << 1) + - g_vol->cluster_size - 1) & - ~(g_vol->cluster_size - 1), - g_vol->upcase_len << 1, - FILE_ATTR_HIDDEN | FILE_ATTR_SYSTEM, 0, 0, - "$UpCase", FILE_NAME_WIN32_AND_DOS); - if (err < 0) { - ntfs_log_error("Couldn't create $UpCase: %s\n", strerror(-err)); - return FALSE; - } - ntfs_log_verbose("Creating $Extend (mft record 11)\n"); - /* - * $Extend index must be resident. Otherwise, w2k3 will regard the - * volume as corrupt. (ERSO) - */ - m = (MFT_RECORD*)(g_buf + 11 * g_vol->mft_record_size); - m->flags |= MFT_RECORD_IS_DIRECTORY; - if (!err) - err = create_hardlink(g_index_block, root_ref, m, - MK_LE_MREF(11, 11), 0LL, 0LL, - FILE_ATTR_HIDDEN | FILE_ATTR_SYSTEM | - FILE_ATTR_I30_INDEX_PRESENT, 0, 0, - "$Extend", FILE_NAME_WIN32_AND_DOS); - /* FIXME: This should be IGNORE_CASE */ - if (!err) - err = add_attr_index_root(m, "$I30", 4, 0, AT_FILE_NAME, - COLLATION_FILE_NAME, g_vol->indx_record_size); - if (err < 0) { - ntfs_log_error("Couldn't create $Extend: %s\n", - strerror(-err)); - return FALSE; - } - /* NTFS reserved system files (mft records 0xc-0xf) */ - for (i = 0xc; i < 0x10; i++) { - ntfs_log_verbose("Creating system file (mft record 0x%x)\n", i); - m = (MFT_RECORD*)(g_buf + i * g_vol->mft_record_size); - err = add_attr_data(m, NULL, 0, 0, 0, NULL, 0); - if (!err) { - init_system_file_sd(i, &sd, &j); - err = add_attr_sd(m, sd, j); - } - if (err < 0) { - ntfs_log_error("Couldn't create system file %i (0x%x): " - "%s\n", i, i, strerror(-err)); - return FALSE; - } - } - /* create systemfiles for ntfs volumes (3.1) */ - /* starting with file 24 (ignoring file 16-23) */ - extend_flags = FILE_ATTR_HIDDEN | FILE_ATTR_SYSTEM | - FILE_ATTR_ARCHIVE | FILE_ATTR_VIEW_INDEX_PRESENT; - ntfs_log_verbose("Creating $Quota (mft record 24)\n"); - m = (MFT_RECORD*)(g_buf + 24 * g_vol->mft_record_size); - m->flags |= MFT_RECORD_IS_4; - m->flags |= MFT_RECORD_IS_VIEW_INDEX; - if (!err) - err = create_hardlink_res((MFT_RECORD*)(g_buf + - 11 * g_vol->mft_record_size), extend_ref, m, - MK_LE_MREF(24, 1), 0LL, 0LL, extend_flags, - 0, 0, "$Quota", FILE_NAME_WIN32_AND_DOS); - /* FIXME: This should be IGNORE_CASE */ - if (!err) - err = add_attr_index_root(m, "$Q", 2, 0, AT_UNUSED, - COLLATION_NTOFS_ULONG, g_vol->indx_record_size); - /* FIXME: This should be IGNORE_CASE */ - if (!err) - err = add_attr_index_root(m, "$O", 2, 0, AT_UNUSED, - COLLATION_NTOFS_SID, g_vol->indx_record_size); - if (!err) - err = initialize_quota(m); - if (err < 0) { - ntfs_log_error("Couldn't create $Quota: %s\n", strerror(-err)); - return FALSE; - } - ntfs_log_verbose("Creating $ObjId (mft record 25)\n"); - m = (MFT_RECORD*)(g_buf + 25 * g_vol->mft_record_size); - m->flags |= MFT_RECORD_IS_4; - m->flags |= MFT_RECORD_IS_VIEW_INDEX; - if (!err) - err = create_hardlink_res((MFT_RECORD*)(g_buf + - 11 * g_vol->mft_record_size), extend_ref, - m, MK_LE_MREF(25, 1), 0LL, 0LL, - extend_flags, 0, 0, "$ObjId", - FILE_NAME_WIN32_AND_DOS); - - /* FIXME: This should be IGNORE_CASE */ - if (!err) - err = add_attr_index_root(m, "$O", 2, 0, AT_UNUSED, - COLLATION_NTOFS_ULONGS, - g_vol->indx_record_size); -#ifdef ENABLE_UUID - if (!err) - err = index_obj_id_insert(m, &g_vol->guid, - MK_LE_MREF(FILE_Volume, FILE_Volume)); -#endif - if (err < 0) { - ntfs_log_error("Couldn't create $ObjId: %s\n", - strerror(-err)); - return FALSE; - } - ntfs_log_verbose("Creating $Reparse (mft record 26)\n"); - m = (MFT_RECORD*)(g_buf + 26 * g_vol->mft_record_size); - m->flags |= MFT_RECORD_IS_4; - m->flags |= MFT_RECORD_IS_VIEW_INDEX; - if (!err) - err = create_hardlink_res((MFT_RECORD*)(g_buf + - 11 * g_vol->mft_record_size), - extend_ref, m, MK_LE_MREF(26, 1), - 0LL, 0LL, extend_flags, 0, 0, - "$Reparse", FILE_NAME_WIN32_AND_DOS); - /* FIXME: This should be IGNORE_CASE */ - if (!err) - err = add_attr_index_root(m, "$R", 2, 0, AT_UNUSED, - COLLATION_NTOFS_ULONGS, g_vol->indx_record_size); - if (err < 0) { - ntfs_log_error("Couldn't create $Reparse: %s\n", - strerror(-err)); - return FALSE; - } - return TRUE; -} - -/** - * mkntfs_redirect - */ -static int mkntfs_redirect(struct mkntfs_options *opts2) -{ - int result = 1; - ntfs_attr_search_ctx *ctx = NULL; - long long lw, pos; - ATTR_RECORD *a; - MFT_RECORD *m; - int i, err; - - if (!opts2) { - ntfs_log_error("Internal error: invalid parameters to mkntfs_options.\n"); - goto done; - } - /* Initialize the random number generator with the current time. */ - srandom(mkntfs_time()); - /* Allocate and initialize ntfs_volume structure g_vol. */ - g_vol = ntfs_volume_alloc(); - if (!g_vol) { - ntfs_log_perror("Could not create volume"); - goto done; - } - /* Create NTFS 3.1 (Windows XP/Vista) volumes. */ - g_vol->major_ver = 3; - g_vol->minor_ver = 1; - /* Transfer some options to the volume. */ - if (opts.label) { - g_vol->vol_name = strdup(opts.label); - if (!g_vol->vol_name) { - ntfs_log_perror("Could not copy volume name"); - goto done; - } - } - if (opts.cluster_size >= 0) - g_vol->cluster_size = opts.cluster_size; - /* Length is in unicode characters. */ - g_vol->upcase_len = 65536; - g_vol->upcase = ntfs_malloc(g_vol->upcase_len * sizeof(ntfschar)); - if (!g_vol->upcase) - goto done; - ntfs_upcase_table_build(g_vol->upcase, - g_vol->upcase_len * sizeof(ntfschar)); - g_vol->attrdef = ntfs_malloc(sizeof(attrdef_ntfs3x_array)); - if (!g_vol->attrdef) { - ntfs_log_perror("Could not create attrdef structure"); - goto done; - } - memcpy(g_vol->attrdef, attrdef_ntfs3x_array, - sizeof(attrdef_ntfs3x_array)); - g_vol->attrdef_len = sizeof(attrdef_ntfs3x_array); - /* Open the partition. */ - if (!mkntfs_open_partition(g_vol)) - goto done; - /* - * Decide on the sector size, cluster size, mft record and index record - * sizes as well as the number of sectors/tracks/heads/size, etc. - */ - if (!mkntfs_override_vol_params(g_vol)) - goto done; - /* Initialize $Bitmap and $MFT/$BITMAP related stuff. */ - if (!mkntfs_initialize_bitmaps()) - goto done; - /* Initialize MFT & set g_logfile_lcn. */ - if (!mkntfs_initialize_rl_mft()) - goto done; - /* Initialize $LogFile. */ - if (!mkntfs_initialize_rl_logfile()) - goto done; - /* Initialize $Boot. */ - if (!mkntfs_initialize_rl_boot()) - goto done; - /* Allocate a buffer large enough to hold the mft. */ - g_buf = ntfs_calloc(g_mft_size); - if (!g_buf) - goto done; - /* Create runlist for $BadClus, $DATA named stream $Bad. */ - if (!mkntfs_initialize_rl_bad()) - goto done; - /* If not quick format, fill the device with 0s. */ - if (!opts.quick_format) { - if (!mkntfs_fill_device_with_zeroes()) - goto done; - } - /* Create NTFS volume structures. */ - if (!mkntfs_create_root_structures()) - goto done; - /* - * - Do not step onto bad blocks!!! - * - If any bad blocks were specified or found, modify $BadClus, - * allocating the bad clusters in $Bitmap. - * - C&w bootsector backup bootsector (backup in last sector of the - * partition). - * - If NTFS 3.0+, c&w $Secure file and $Extend directory with the - * corresponding special files in it, i.e. $ObjId, $Quota, $Reparse, - * and $UsnJrnl. And others? Or not all necessary? - * - RE: Populate $root with the system files (and $Extend directory if - * applicable). Possibly should move this as far to the top as - * possible and update during each subsequent c&w of each system file. - */ - ntfs_log_verbose("Syncing root directory index record.\n"); - if (!mkntfs_sync_index_record(g_index_block, (MFT_RECORD*)(g_buf + 5 * - g_vol->mft_record_size), NTFS_INDEX_I30, 4)) - goto done; - - ntfs_log_verbose("Syncing $Bitmap.\n"); - m = (MFT_RECORD*)(g_buf + 6 * g_vol->mft_record_size); - - ctx = ntfs_attr_get_search_ctx(NULL, m); - if (!ctx) { - ntfs_log_perror("Could not create an attribute search context"); - goto done; - } - - if (mkntfs_attr_lookup(AT_DATA, AT_UNNAMED, 0, 0, 0, NULL, 0, ctx)) { - ntfs_log_error("BUG: $DATA attribute not found.\n"); - goto done; - } - - a = ctx->attr; - if (a->non_resident) { - runlist *rl = ntfs_mapping_pairs_decompress(g_vol, a, NULL); - if (!rl) { - ntfs_log_error("ntfs_mapping_pairs_decompress() failed\n"); - goto done; - } - lw = ntfs_rlwrite(g_vol->u.dev, rl, g_lcn_bitmap, g_lcn_bitmap_byte_size, NULL); - err = errno; - free(rl); - if (lw != g_lcn_bitmap_byte_size) { - ntfs_log_error("ntfs_rlwrite: %s\n", lw == -1 ? - strerror(err) : "unknown error"); - goto done; - } - } else { - memcpy((char*)a + le16_to_cpu(a->u.res.value_offset), g_lcn_bitmap, le32_to_cpu(a->u.res.value_length)); - } - - /* - * No need to sync $MFT/$BITMAP as that has never been modified since - * its creation. - */ - ntfs_log_verbose("Syncing $MFT.\n"); - pos = g_mft_lcn * g_vol->cluster_size; - lw = 1; - for (i = 0; i < g_mft_size / (s32)g_vol->mft_record_size; i++) { - if (!opts.no_action) - lw = ntfs_mst_pwrite(g_vol->u.dev, pos, 1, g_vol->mft_record_size, g_buf + i * g_vol->mft_record_size); - if (lw != 1) { - ntfs_log_error("ntfs_mst_pwrite: %s\n", lw == -1 ? - strerror(errno) : "unknown error"); - goto done; - } - pos += g_vol->mft_record_size; - } - ntfs_log_verbose("Updating $MFTMirr.\n"); - pos = g_mftmirr_lcn * g_vol->cluster_size; - lw = 1; - for (i = 0; i < g_rl_mftmirr[0].length * g_vol->cluster_size / g_vol->mft_record_size; i++) { - m = (MFT_RECORD*)(g_buf + i * g_vol->mft_record_size); - /* - * Decrement the usn by one, so it becomes the same as the one - * in $MFT once it is mst protected. - This is as we need the - * $MFTMirr to have the exact same byte by byte content as - * $MFT, rather than just equivalent meaning content. - */ - if (ntfs_mft_usn_dec(m)) { - ntfs_log_error("ntfs_mft_usn_dec"); - goto done; - } - if (!opts.no_action) - lw = ntfs_mst_pwrite(g_vol->u.dev, pos, 1, g_vol->mft_record_size, g_buf + i * g_vol->mft_record_size); - if (lw != 1) { - ntfs_log_error("ntfs_mst_pwrite: %s\n", lw == -1 ? - strerror(errno) : "unknown error"); - goto done; - } - pos += g_vol->mft_record_size; - } - ntfs_log_verbose("Syncing device.\n"); - if (g_vol->u.dev->d_ops->sync(g_vol->u.dev)) { - ntfs_log_error("Syncing device. FAILED"); - goto done; - } - ntfs_log_quiet("mkntfs completed successfully. Have a nice day.\n"); - result = 0; -done: - ntfs_attr_put_search_ctx(ctx); - mkntfs_cleanup(); /* Device is unlocked and closed here */ - return result; -} - - -/** - * main - Begin here - * - * Start from here. - * - * Return: 0 Success, the program worked - * 1 Error, something went wrong - */ -int main(int argc, char *argv[]) -{ - int result = 1; - - ntfs_log_set_handler(ntfs_log_handler_outerr); - utils_set_locale(); - - mkntfs_init_options(&opts); /* Set up the options */ - - if (!mkntfs_parse_options(argc, argv, &opts)) /* Read the command line options */ - goto done; - - result = mkntfs_redirect(&opts); -done: - return result; -} diff --git a/usr/src/cmd/ntfsprogs/ntfscat.c b/usr/src/cmd/ntfsprogs/ntfscat.c deleted file mode 100644 index 3fe604629d..0000000000 --- a/usr/src/cmd/ntfsprogs/ntfscat.c +++ /dev/null @@ -1,441 +0,0 @@ -/** - * ntfscat - Part of the Linux-NTFS project. - * - * Copyright (c) 2003-2005 Richard Russon - * Copyright (c) 2003-2005 Anton Altaparmakov - * Copyright (c) 2003-2005 Szabolcs Szakacsits - * Copyright (c) 2007 Yura Pakhuchiy - * - * This utility will concatenate files and print on the standard output. - * - * 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 Linux-NTFS - * 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_STDIO_H -#include <stdio.h> -#endif -#ifdef HAVE_GETOPT_H -#include <getopt.h> -#endif -#ifdef HAVE_STDLIB_H -#include <stdlib.h> -#endif -#ifdef HAVE_STRING_H -#include <string.h> -#endif - -#include "compat.h" -#include "types.h" -#include "attrib.h" -#include "utils.h" -#include "volume.h" -#include "debug.h" -#include "dir.h" -#include "ntfscat.h" -#include "version.h" - -static const char *EXEC_NAME = "ntfscat"; -static struct options opts; - -/** - * version - Print version information about the program - * - * Print a copyright statement and a brief description of the program. - * - * Return: none - */ -static void version(void) -{ - ntfs_log_info("\n%s v%s (libntfs %s) - Concatenate files and print " - "on the standard output.\n\n", EXEC_NAME, VERSION, - ntfs_libntfs_version()); - ntfs_log_info("Copyright (c) 2003-2005 Richard Russon\n"); - ntfs_log_info("Copyright (c) 2003-2005 Anton Altaparmakov\n"); - ntfs_log_info("Copyright (c) 2003-2005 Szabolcs Szakacsits\n"); - ntfs_log_info("Copyright (c) 2007 Yura Pakhuchiy\n"); - ntfs_log_info("\n%s\n%s%s\n", ntfs_gpl, ntfs_bugs, ntfs_home); -} - -/** - * usage - Print a list of the parameters to the program - * - * Print a list of the parameters and options for the program. - * - * Return: none - */ -static void usage(void) -{ - ntfs_log_info("\nUsage: %s [options] device [file]\n\n" - " -a, --attribute TYPE Display this attribute type\n" - " -n, --attribute-name NAME Display this attribute name\n" - " -i, --inode NUM Display this inode\n\n" - " -f, --force Use less caution\n" - " -h, --help Print this help\n" - " -q, --quiet Less output\n" - " -V, --version Version information\n" - " -v, --verbose More output\n\n", -// Does not work for compressed files at present so leave undocumented... -// " -r --raw Display the raw data (e.g. for compressed or encrypted file)", - EXEC_NAME); - ntfs_log_info("%s%s\n", ntfs_bugs, ntfs_home); -} - -/** - * parse_attribute - Read an attribute name, or number - * @value: String to be parsed - * @attr: Resulting attribute id (on success) - * - * Read a string representing an attribute. It may be a decimal, octal or - * hexadecimal number, or the attribute name in full. The leading $ sign is - * optional. - * - * Return: 1 Success, a valid attribute name or number - * 0 Error, not an attribute name or number - */ -static int parse_attribute(const char *value, ATTR_TYPES *attr) -{ - static const char *attr_name[] = { - "$STANDARD_INFORMATION", - "$ATTRIBUTE_LIST", - "$FILE_NAME", - "$OBJECT_ID", - "$SECURITY_DESCRIPTOR", - "$VOLUME_NAME", - "$VOLUME_INFORMATION", - "$DATA", - "$INDEX_ROOT", - "$INDEX_ALLOCATION", - "$BITMAP", - "$REPARSE_POINT", - "$EA_INFORMATION", - "$EA", - "$PROPERTY_SET", - "$LOGGED_UTILITY_STREAM", - NULL - }; - - int i; - long num; - - for (i = 0; attr_name[i]; i++) { - if ((strcmp(value, attr_name[i]) == 0) || - (strcmp(value, attr_name[i] + 1) == 0)) { - *attr = (ATTR_TYPES)cpu_to_le32((i + 1) * 16); - return 1; - } - } - - num = strtol(value, NULL, 0); - if ((num > 0) && (num < 257)) { - *attr = (ATTR_TYPES)cpu_to_le32(num); - return 1; - } - - return 0; -} - -/** - * parse_options - Read and validate the programs command line - * - * Read the command line, verify the syntax and parse the options. - * This function is very long, but quite simple. - * - * Return: 1 Success - * 0 Error, one or more problems - */ -static int parse_options(int argc, char **argv) -{ - static const char *sopt = "-a:fh?i:n:qVvr"; - static const struct option lopt[] = { - { "attribute", required_argument, NULL, 'a' }, - { "attribute-name", required_argument, NULL, 'n' }, - { "force", no_argument, NULL, 'f' }, - { "help", no_argument, NULL, 'h' }, - { "inode", required_argument, NULL, 'i' }, - { "quiet", no_argument, NULL, 'q' }, - { "version", no_argument, NULL, 'V' }, - { "verbose", no_argument, NULL, 'v' }, - { "raw", no_argument, NULL, 'r' }, - { NULL, 0, NULL, 0 } - }; - - int c = -1; - int err = 0; - int ver = 0; - int help = 0; - int levels = 0; - ATTR_TYPES attr = AT_UNUSED; - - opterr = 0; /* We'll handle the errors, thank you. */ - - opts.inode = -1; - opts.attr = cpu_to_le32(-1); - opts.attr_name = NULL; - opts.attr_name_len = 0; - - while ((c = getopt_long(argc, argv, sopt, lopt, NULL)) != -1) { - switch (c) { - case 1: /* A non-option argument */ - if (!opts.device) { - opts.device = argv[optind - 1]; - } else if (!opts.file) { - opts.file = argv[optind - 1]; - } else { - ntfs_log_error("You must specify exactly one " - "file.\n"); - err++; - } - break; - case 'a': - if (opts.attr != cpu_to_le32(-1)) { - ntfs_log_error("You must specify exactly one " - "attribute.\n"); - } else if (parse_attribute(optarg, &attr) > 0) { - opts.attr = attr; - break; - } else { - ntfs_log_error("Couldn't parse attribute.\n"); - } - err++; - break; - case 'f': - opts.force++; - break; - case 'h': - case '?': - if (strncmp (argv[optind-1], "--log-", 6) == 0) { - if (!ntfs_log_parse_option (argv[optind-1])) - err++; - break; - } - help++; - break; - case 'i': - if (opts.inode != -1) - ntfs_log_error("You must specify exactly one inode.\n"); - else if (utils_parse_size(optarg, &opts.inode, FALSE)) - break; - else - ntfs_log_error("Couldn't parse inode number.\n"); - err++; - break; - - case 'n': - opts.attr_name_len = ntfs_mbstoucs(optarg, - &opts.attr_name, 0); - if (opts.attr_name_len < 0) { - ntfs_log_perror("Invalid attribute name '%s'", - optarg); - usage(); - } - - case 'q': - opts.quiet++; - ntfs_log_clear_levels(NTFS_LOG_LEVEL_QUIET); - break; - case 'V': - ver++; - break; - case 'v': - opts.verbose++; - ntfs_log_set_levels(NTFS_LOG_LEVEL_VERBOSE); - break; - case 'r': - opts.raw = TRUE; - break; - default: - ntfs_log_error("Unknown option '%s'.\n", argv[optind-1]); - err++; - break; - } - } - - /* Make sure we're in sync with the log levels */ - levels = ntfs_log_get_levels(); - if (levels & NTFS_LOG_LEVEL_VERBOSE) - opts.verbose++; - if (!(levels & NTFS_LOG_LEVEL_QUIET)) - opts.quiet++; - - if (help || ver) { - opts.quiet = 0; - } else { - if (opts.device == NULL) { - ntfs_log_error("You must specify a device.\n"); - err++; - - } else if (opts.file == NULL && opts.inode == -1) { - ntfs_log_error("You must specify a file or inode " - "with the -i option.\n"); - err++; - - } else if (opts.file != NULL && opts.inode != -1) { - ntfs_log_error("You can't specify both a file and inode.\n"); - err++; - } - - if (opts.quiet && opts.verbose) { - ntfs_log_error("You may not use --quiet and --verbose at the " - "same time.\n"); - err++; - } - } - - if (ver) - version(); - if (help || err) - usage(); - - return (!err && !help && !ver); -} - -/** - * index_get_size - Find the INDX block size from the index root - * @inode: Inode of the directory to be checked - * - * Find the size of a directory's INDX block from the INDEX_ROOT attribute. - * - * Return: n Success, the INDX blocks are n bytes in size - * 0 Error, not a directory - */ -static int index_get_size(ntfs_inode *inode) -{ - ATTR_RECORD *attr90; - INDEX_ROOT *iroot; - - attr90 = find_first_attribute(AT_INDEX_ROOT, inode->mrec); - if (!attr90) - return 0; // not a directory - - iroot = (INDEX_ROOT*)((u8*)attr90 + le16_to_cpu(attr90->u.res.value_offset)); - return le32_to_cpu(iroot->index_block_size); -} - -/** - * cat - */ -static int cat(ntfs_volume *vol, ntfs_inode *inode, ATTR_TYPES type, - ntfschar *name, int namelen) -{ - const int bufsize = 4096; - char *buffer; - ntfs_attr *attr; - s64 bytes_read, written; - s64 offset; - u32 block_size; - - buffer = malloc(bufsize); - if (!buffer) - return 1; - - attr = ntfs_attr_open(inode, type, name, namelen); - if (!attr) { - ntfs_log_error("Cannot find attribute type 0x%x.\n", - le32_to_cpu(type)); - free(buffer); - return 1; - } - - if ((inode->mft_no < 2) && (attr->type == AT_DATA)) - block_size = vol->mft_record_size; - else if (attr->type == AT_INDEX_ALLOCATION) - block_size = index_get_size(inode); - else - block_size = 0; - - offset = 0; - for (;;) { - if (!opts.raw && block_size > 0) { - // These types have fixup - bytes_read = ntfs_attr_mst_pread(attr, offset, 1, block_size, buffer); - if (bytes_read > 0) - bytes_read *= block_size; - } else { - bytes_read = ntfs_attr_pread(attr, offset, bufsize, buffer); - } - //ntfs_log_info("read %lld bytes\n", bytes_read); - if (bytes_read == -1) { - ntfs_log_perror("ERROR: Couldn't read file"); - break; - } - if (!bytes_read) - break; - - written = fwrite(buffer, 1, bytes_read, stdout); - if (written != bytes_read) { - ntfs_log_perror("ERROR: Couldn't output all data!"); - break; - } - offset += bytes_read; - } - - ntfs_attr_close(attr); - free(buffer); - return 0; -} - -/** - * main - Begin here - * - * Start from here. - * - * Return: 0 Success, the program worked - * 1 Error, something went wrong - */ -int main(int argc, char *argv[]) -{ - ntfs_volume *vol; - ntfs_inode *inode; - ATTR_TYPES attr; - int result = 1; - - ntfs_log_set_handler(ntfs_log_handler_stderr); - - if (!parse_options(argc, argv)) - return 1; - - utils_set_locale(); - - vol = utils_mount_volume(opts.device, NTFS_MNT_RDONLY | - (opts.force ? NTFS_MNT_FORCE : 0)); - if (!vol) { - ntfs_log_perror("ERROR: couldn't mount volume"); - return 1; - } - - if (opts.inode != -1) - inode = ntfs_inode_open(vol, opts.inode); - else - inode = ntfs_pathname_to_inode(vol, NULL, opts.file); - - if (!inode) { - ntfs_log_perror("ERROR: Couldn't open inode"); - return 1; - } - - attr = AT_DATA; - if (opts.attr != cpu_to_le32(-1)) - attr = opts.attr; - - result = cat(vol, inode, attr, opts.attr_name, opts.attr_name_len); - - ntfs_inode_close(inode); - ntfs_umount(vol, FALSE); - - return result; -} diff --git a/usr/src/cmd/ntfsprogs/ntfscat.h b/usr/src/cmd/ntfsprogs/ntfscat.h deleted file mode 100644 index cf474b4889..0000000000 --- a/usr/src/cmd/ntfsprogs/ntfscat.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * ntfscat - Part of the Linux-NTFS project. - * - * Copyright (c) 2003 Richard Russon - * Copyright (c) 2003 Anton Altaparmakov - * - * This utility will concatenate files and print on the standard output. - * - * 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 Linux-NTFS - * 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 _NTFSCAT_H_ -#define _NTFSCAT_H_ - -#include "types.h" -#include "layout.h" - -struct options { - char *device; /* Device/File to work with */ - char *file; /* File to display */ - s64 inode; /* Inode to work with */ - ATTR_TYPES attr; /* Attribute type to display */ - ntfschar *attr_name; /* Attribute name to display */ - int attr_name_len; /* Attribute name length */ - int force; /* Override common sense */ - int quiet; /* Less output */ - int verbose; /* Extra output */ - BOOL raw; /* Raw data output */ -}; - -#endif /* _NTFSCAT_H_ */ - - diff --git a/usr/src/cmd/ntfsprogs/ntfsclone.c b/usr/src/cmd/ntfsprogs/ntfsclone.c deleted file mode 100644 index bb63475ef0..0000000000 --- a/usr/src/cmd/ntfsprogs/ntfsclone.c +++ /dev/null @@ -1,1926 +0,0 @@ -/** - * ntfsclone - Part of the Linux-NTFS project. - * - * Copyright (c) 2003-2006 Szabolcs Szakacsits - * Copyright (c) 2004-2006 Anton Altaparmakov - * Special image format support copyright (c) 2004 Per Olofsson - * - * Clone NTFS data and/or metadata to a sparse file, image, device or stdout. - * - * 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. - */ - -#include "config.h" - -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif -#ifdef HAVE_STDLIB_H -#include <stdlib.h> -#endif -#ifdef HAVE_STDIO_H -#include <stdio.h> -#endif -#ifdef HAVE_SYS_TYPES_H -#include <sys/types.h> -#endif -#ifdef HAVE_SYS_STAT_H -#include <sys/stat.h> -#endif -#ifdef HAVE_SYS_IOCTL_H -#include <sys/ioctl.h> -#endif -#ifdef HAVE_SYS_VFS_H -#include <sys/vfs.h> -#endif -#ifdef HAVE_SYS_STATVFS_H -#include <sys/statvfs.h> -#endif -#ifdef HAVE_FCNTL_H -#include <fcntl.h> -#endif -#ifdef HAVE_STDARG_H -#include <stdarg.h> -#endif -#ifdef HAVE_STRING_H -#include <string.h> -#endif -#ifdef HAVE_ERRNO_H -#include <errno.h> -#endif -#ifdef HAVE_GETOPT_H -#include <getopt.h> -#endif - -/* - * FIXME: ntfsclone do bad things about endians handling. Fix it and remove - * this note and define. - */ -#define NTFS_DO_NOT_CHECK_ENDIANS - -#include "compat.h" -#include "debug.h" -#include "types.h" -#include "support.h" -#include "endians.h" -#include "bootsect.h" -#include "device.h" -#include "attrib.h" -#include "mst.h" -#include "volume.h" -#include "mft.h" -#include "bitmap.h" -#include "inode.h" -#include "index.h" -#include "dir.h" -#include "runlist.h" -#include "ntfstime.h" -#include "utils.h" -#include "version.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 - -static const char *EXEC_NAME = "ntfsclone"; - -static const char *bad_sectors_warning_msg = -"*************************************************************************\n" -"* WARNING: The disk has bad sector. This means physical damage on the *\n" -"* disk surface caused by deterioration, manufacturing faults or other *\n" -"* reason. The reliability of the disk may stay stable or degrade fast. *\n" -"* Use the --rescue option to efficiently save as much data as possible! *\n" -"*************************************************************************\n"; - -static const char *dirty_volume_msg = -"Volume '%s' is scheduled for a check or it was shutdown \n" -"uncleanly. Please boot Windows or use the --force option to progress.\n"; - -static struct { - int verbose; - int quiet; - int debug; - int force; - int overwrite; - int std_out; - int blkdev_out; /* output file is block device */ - int metadata; /* metadata only cloning */ - int ignore_fs_check; - int rescue; - int save_image; - int restore_image; - char *output; - char *volume; -#ifdef __sun - struct statvfs stfs; -#else - struct statfs stfs; -#endif -} opt; - -struct bitmap { - s64 size; - u8 *bm; -}; - -struct progress_bar { - u64 start; - u64 stop; - int resolution; - float unit; -}; - -typedef struct { - ntfs_inode *ni; /* inode being processed */ - ntfs_attr_search_ctx *ctx; /* inode attribute being processed */ - s64 inuse; /* number of clusters in use */ -} ntfs_walk_clusters_ctx; - -typedef int (ntfs_walk_op)(ntfs_inode *ni, void *data); - -struct ntfs_walk_cluster { - ntfs_walk_op *inode_op; /* not implemented yet */ - ntfs_walk_clusters_ctx *image; -}; - - -static ntfs_volume *vol = NULL; -static struct bitmap lcn_bitmap; - -static int fd_in; -static int fd_out; -static FILE *msg_out = NULL; - -static int wipe = 0; -static unsigned int nr_used_mft_records = 0; -static unsigned int wiped_unused_mft_data = 0; -static unsigned int wiped_unused_mft = 0; -static unsigned int wiped_resident_data = 0; -static unsigned int wiped_timestamp_data = 0; - -static BOOL image_is_host_endian = FALSE; - -#define IMAGE_MAGIC "\0ntfsclone-image" -#define IMAGE_MAGIC_SIZE 16 - -/* This is the first endianness safe format version. */ -#define NTFSCLONE_IMG_VER_MAJOR_ENDIANNESS_SAFE 10 -#define NTFSCLONE_IMG_VER_MINOR_ENDIANNESS_SAFE 0 - -/* - * Set the version to 10.0 to avoid colisions with old ntfsclone which - * stupidly used the volume version as the image version... )-: I hope NTFS - * never reaches version 10.0 and if it does one day I hope no-one is using - * such an old ntfsclone by then... - * - * NOTE: Only bump the minor version if the image format and header are still - * backwards compatible. Otherwise always bump the major version. If in - * doubt, bump the major version. - */ -#define NTFSCLONE_IMG_VER_MAJOR 10 -#define NTFSCLONE_IMG_VER_MINOR 0 - -/* All values are in little endian. */ -#ifdef __sun -#pragma pack(1) -#endif -static struct image_hdr { - char magic[IMAGE_MAGIC_SIZE]; - u8 major_ver; - u8 minor_ver; - u32 cluster_size; - s64 device_size; - s64 nr_clusters; - s64 inuse; - u32 offset_to_image_data; /* From start of image_hdr. */ -} __attribute__((__packed__)) image_hdr; -#ifdef __sun -#pragma pack() -#endif - -#ifdef __sun -#define NTFSCLONE_IMG_HEADER_SIZE_OLD \ - (offsetof(struct image_hdr, offset_to_image_data)) -#else -#define NTFSCLONE_IMG_HEADER_SIZE_OLD \ - (offsetof(typeof(image_hdr), offset_to_image_data)) -#endif - -#define NTFS_MBYTE (1000 * 1000) - -#define ERR_PREFIX "ERROR" -#define PERR_PREFIX ERR_PREFIX "(%d): " -#define NERR_PREFIX ERR_PREFIX ": " - -#define LAST_METADATA_INODE 11 - -#define NTFS_MAX_CLUSTER_SIZE 65536 -#define NTFS_SECTOR_SIZE 512 - -#define rounded_up_division(a, b) (((a) + (b - 1)) / (b)) - -#define read_all(f, p, n) io_all((f), (p), (n), 0) -#define write_all(f, p, n) io_all((f), (p), (n), 1) - -__attribute__((format(printf, 1, 2))) -static void Printf(const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - vfprintf(msg_out, fmt, ap); - va_end(ap); - fflush(msg_out); -} - -__attribute__((format(printf, 1, 2))) -static void perr_printf(const char *fmt, ...) -{ - va_list ap; - int eo = errno; - - Printf(PERR_PREFIX, eo); - va_start(ap, fmt); - vfprintf(msg_out, fmt, ap); - va_end(ap); - Printf(": %s\n", strerror(eo)); - fflush(msg_out); -} - -__attribute__((format(printf, 1, 2))) -static void err_printf(const char *fmt, ...) -{ - va_list ap; - - Printf(NERR_PREFIX); - va_start(ap, fmt); - vfprintf(msg_out, fmt, ap); - va_end(ap); - fflush(msg_out); -} - -__attribute__((noreturn)) -__attribute__((format(printf, 1, 2))) -static int err_exit(const char *fmt, ...) -{ - va_list ap; - - Printf(NERR_PREFIX); - va_start(ap, fmt); - vfprintf(msg_out, fmt, ap); - va_end(ap); - fflush(msg_out); - exit(1); -} - -__attribute__((noreturn)) -__attribute__((format(printf, 1, 2))) -static int perr_exit(const char *fmt, ...) -{ - va_list ap; - int eo = errno; - - Printf(PERR_PREFIX, eo); - va_start(ap, fmt); - vfprintf(msg_out, fmt, ap); - va_end(ap); - Printf(": %s\n", strerror(eo)); - fflush(msg_out); - exit(1); -} - - -__attribute__((noreturn)) -static void usage(void) -{ - fprintf(stderr, "\nUsage: %s [OPTIONS] SOURCE\n" - " Efficiently clone NTFS to a sparse file, image, device or standard output.\n" - "\n" - " -o, --output FILE Clone NTFS to the non-existent FILE\n" - " -O, --overwrite FILE Clone NTFS to FILE, overwriting if exists\n" - " -s, --save-image Save to the special image format\n" - " -r, --restore-image Restore from the special image format\n" - " --rescue Continue after disk read errors\n" - " -m, --metadata Clone *only* metadata (for NTFS experts)\n" - " --ignore-fs-check Ignore the filesystem check result\n" - " -f, --force Force to progress (DANGEROUS)\n" - " -h, --help Display this help\n" -#ifdef DEBUG - " -d, --debug Show debug information\n" -#endif - "\n" - " If FILE is '-' then send the image to the standard output. If SOURCE is '-'\n" - " and --restore-image is used then read the image from the standard input.\n" - "\n", EXEC_NAME); - fprintf(stderr, "%s%s", ntfs_bugs, ntfs_home); - exit(1); -} - - -static void parse_options(int argc, char **argv) -{ - static const char *sopt = "-dfhmo:O:rs"; - static const struct option lopt[] = { -#ifdef DEBUG - { "debug", no_argument, NULL, 'd' }, -#endif - { "force", no_argument, NULL, 'f' }, - { "help", no_argument, NULL, 'h' }, - { "metadata", no_argument, NULL, 'm' }, - { "output", required_argument, NULL, 'o' }, - { "overwrite", required_argument, NULL, 'O' }, - { "restore-image", no_argument, NULL, 'r' }, - { "ignore-fs-check", no_argument, NULL, 'C' }, - { "rescue", no_argument, NULL, 'R' }, - { "save-image", no_argument, NULL, 's' }, - { NULL, 0, NULL, 0 } - }; - - int c; - - memset(&opt, 0, sizeof(opt)); - - while ((c = getopt_long(argc, argv, sopt, lopt, NULL)) != -1) { - switch (c) { - case 1: /* A non-option argument */ - if (opt.volume) - usage(); - opt.volume = argv[optind-1]; - break; - case 'd': - opt.debug++; - break; - case 'f': - opt.force++; - break; - case 'h': - case '?': - usage(); - case 'm': - opt.metadata++; - break; - case 'O': - opt.overwrite++; - case 'o': - if (opt.output) - usage(); - opt.output = optarg; - break; - case 'r': - opt.restore_image++; - break; - case 'C': - opt.ignore_fs_check++; - break; - case 'R': - opt.rescue++; - break; - case 's': - opt.save_image++; - break; - default: - err_printf("Unknown option '%s'.\n", argv[optind-1]); - usage(); - } - } - - if (opt.output == NULL) { - err_printf("You must specify an output file.\n"); - usage(); - } - - if (strcmp(opt.output, "-") == 0) - opt.std_out++; - - if (opt.volume == NULL) { - err_printf("You must specify a device file.\n"); - usage(); - } - - if (opt.metadata && opt.save_image) - err_exit("Saving only metadata to an image is not " - "supported!\n"); - - if (opt.metadata && opt.restore_image) - err_exit("Restoring only metadata from an image is not " - "supported!\n"); - - if (opt.metadata && opt.std_out) - err_exit("Cloning only metadata to stdout isn't supported!\n"); - - if (opt.ignore_fs_check && !opt.metadata) - err_exit("Filesystem check can be ignored only for metadata " - "cloning!\n"); - - if (opt.save_image && opt.restore_image) - err_exit("Saving and restoring an image at the same time " - "is not supported!\n"); - - if (!opt.std_out) { - struct stat st; - - if (stat(opt.output, &st) == -1) { - if (errno != ENOENT) - perr_exit("Couldn't access '%s'", opt.output); - } else { - if (!opt.overwrite) - err_exit("Output file '%s' already exists.\n" - "Use option --overwrite if you want to" - " replace its content.\n", opt.output); - - if (S_ISBLK(st.st_mode)) { - opt.blkdev_out = 1; - if (opt.metadata) - err_exit("Cloning only metadata to a " - "block device isn't supported!\n"); - } - } - } - - msg_out = stdout; - - /* FIXME: this is a workaround for losing debug info if stdout != stderr - and for the uncontrollable verbose messages in libntfs. Ughhh. */ - if (opt.std_out) - msg_out = stderr; - else if (opt.debug) { - /* Redirect stderr to stdout, note fflush()es are essential! */ - fflush(stdout); - fflush(stderr); - if (dup2(STDOUT_FILENO, STDERR_FILENO) == -1) { - perror("Failed to redirect stderr to stdout"); - exit(1); - } - fflush(stdout); - fflush(stderr); - } else { - fflush(stderr); - if (!freopen("/dev/null", "w", stderr)) - perr_exit("Failed to redirect stderr to /dev/null"); - } -} - -static void progress_init(struct progress_bar *p, u64 start, u64 stop, int res) -{ - p->start = start; - p->stop = stop; - p->unit = 100.0 / (stop - start); - p->resolution = res; -} - - -static void progress_update(struct progress_bar *p, u64 current) -{ - float percent = p->unit * current; - - if (current != p->stop) { - if ((current - p->start) % p->resolution) - return; - Printf("%6.2f percent completed\r", percent); - } else - Printf("100.00 percent completed\n"); - fflush(msg_out); -} - -static s64 is_critical_metadata(ntfs_walk_clusters_ctx *image, runlist *rl) -{ - s64 inode = image->ni->mft_no; - - if (inode <= LAST_METADATA_INODE) { - - /* Don't save bad sectors (both $Bad and unnamed are ignored */ - if (inode == FILE_BadClus && image->ctx->attr->type == AT_DATA) - return 0; - - if (inode != FILE_LogFile) - return rl->length; - - if (image->ctx->attr->type == AT_DATA) { - - /* Save at least the first 16 KiB of FILE_LogFile */ - s64 s = (s64)16384 - rl->vcn * vol->cluster_size; - if (s > 0) { - s = rounded_up_division(s, vol->cluster_size); - if (rl->length < s) - s = rl->length; - return s; - } - return 0; - } - } - - if (image->ctx->attr->type != AT_DATA) - return rl->length; - - return 0; -} - - -static int io_all(void *fd, void *buf, int count, int do_write) -{ - int i; - struct ntfs_device *dev = fd; - - while (count > 0) { - if (do_write) - i = write(*(int *)fd, buf, count); - else if (opt.restore_image) - i = read(*(int *)fd, buf, count); - else - i = dev->d_ops->read(dev, buf, count); - if (i < 0) { - if (errno != EAGAIN && errno != EINTR) - return -1; - } else { - count -= i; - buf = i + (char *) buf; - } - } - return 0; -} - - -static void rescue_sector(void *fd, off_t pos, void *buff) -{ - const char *badsector_magic = "BadSectoR\0"; - struct ntfs_device *dev = fd; - - if (opt.restore_image) { - if (lseek(*(int *)fd, pos, SEEK_SET) == (off_t)-1) - perr_exit("lseek"); - } else { - if (vol->u.dev->d_ops->seek(dev, pos, SEEK_SET) == (off_t)-1) - perr_exit("seek input"); - } - - if (read_all(fd, buff, NTFS_SECTOR_SIZE) == -1) { - Printf("WARNING: Can't read sector at %llu, lost data.\n", - (unsigned long long)pos); - memset(buff, '?', NTFS_SECTOR_SIZE); - memmove(buff, badsector_magic, sizeof(badsector_magic)); - } -} - - -static void copy_cluster(int rescue, u64 rescue_lcn) -{ - char buff[NTFS_MAX_CLUSTER_SIZE]; /* overflow checked at mount time */ - /* vol is NULL if opt.restore_image is set */ - u32 csize = le32_to_cpu(image_hdr.cluster_size); - void *fd = (void *)&fd_in; - off_t rescue_pos; - - if (!opt.restore_image) { - csize = vol->cluster_size; - fd = vol->u.dev; - } - - rescue_pos = (off_t)(rescue_lcn * csize); - - if (read_all(fd, buff, csize) == -1) { - - if (errno != EIO) - perr_exit("read_all"); - else if (rescue){ - u32 i; - for (i = 0; i < csize; i += NTFS_SECTOR_SIZE) - rescue_sector(fd, rescue_pos + i, buff + i); - } else { - Printf("%s", bad_sectors_warning_msg); - err_exit("Disk is faulty, can't make full backup!"); - } - } - - if (opt.save_image) { - char cmd = 1; - if (write_all(&fd_out, &cmd, sizeof(cmd)) == -1) - perr_exit("write_all"); - } - - if (write_all(&fd_out, buff, csize) == -1) { - perr_printf("Write failed"); -#ifndef __sun - int err = errno; - if (errno == EIO && opt.stfs.f_type == 0x517b) - Printf("Apparently you tried to clone to a remote " - "Windows computer but they don't\nhave " - "efficient sparse file handling by default. " - "Please try a different method.\n"); -#endif /* !defined(__sun) */ - exit(1); - } -} - -static void lseek_to_cluster(s64 lcn) -{ - off_t pos; - - pos = (off_t)(lcn * vol->cluster_size); - - if (vol->u.dev->d_ops->seek(vol->u.dev, pos, SEEK_SET) == (off_t)-1) - perr_exit("lseek input"); - - if (opt.std_out || opt.save_image) - return; - - if (lseek(fd_out, pos, SEEK_SET) == (off_t)-1) - perr_exit("lseek output"); -} - -static void image_skip_clusters(s64 count) -{ - if (opt.save_image && count > 0) { -#ifdef __sun - s64 count_buf; -#else - typeof(count) count_buf; -#endif - char buff[1 + sizeof(count)]; - - buff[0] = 0; - count_buf = cpu_to_sle64(count); - memcpy(buff + 1, &count_buf, sizeof(count_buf)); - - if (write_all(&fd_out, buff, sizeof(buff)) == -1) - perr_exit("write_all"); - } -} - -static void dump_clusters(ntfs_walk_clusters_ctx *image, runlist *rl) -{ - s64 i, len; /* number of clusters to copy */ - - if (opt.std_out || !opt.metadata) - return; - - if (!(len = is_critical_metadata(image, rl))) - return; - - lseek_to_cluster(rl->lcn); - - /* FIXME: this could give pretty suboptimal performance */ - for (i = 0; i < len; i++) - copy_cluster(opt.rescue, rl->lcn + i); -} - -static void clone_ntfs(u64 nr_clusters) -{ - u64 cl, last_cl; /* current and last used cluster */ - void *buf; - u32 csize = vol->cluster_size; - u64 p_counter = 0; - struct progress_bar progress; - - if (opt.save_image) - Printf("Saving NTFS to image ...\n"); - else - Printf("Cloning NTFS ...\n"); - - buf = ntfs_calloc(csize); - if (!buf) - perr_exit("clone_ntfs"); - - progress_init(&progress, p_counter, nr_clusters, 100); - - if (opt.save_image) { - if (write_all(&fd_out, &image_hdr, - image_hdr.offset_to_image_data) == -1) - perr_exit("write_all"); - } - - for (last_cl = cl = 0; cl < (u64)vol->nr_clusters; cl++) { - - if (ntfs_bit_get(lcn_bitmap.bm, cl)) { - progress_update(&progress, ++p_counter); - lseek_to_cluster(cl); - image_skip_clusters(cl - last_cl - 1); - - copy_cluster(opt.rescue, cl); - last_cl = cl; - continue; - } - - if (opt.std_out && !opt.save_image) { - progress_update(&progress, ++p_counter); - if (write_all(&fd_out, buf, csize) == -1) - perr_exit("write_all"); - } - } - image_skip_clusters(cl - last_cl - 1); -} - -static void write_empty_clusters(s32 csize, s64 count, - struct progress_bar *progress, u64 *p_counter) -{ - s64 i; - char buff[NTFS_MAX_CLUSTER_SIZE]; - - memset(buff, 0, csize); - - for (i = 0; i < count; i++) { - if (write_all(&fd_out, buff, csize) == -1) - perr_exit("write_all"); - progress_update(progress, ++(*p_counter)); - } -} - -static void restore_image(void) -{ - s64 pos = 0, count; - s32 csize = le32_to_cpu(image_hdr.cluster_size); - char cmd; - u64 p_counter = 0; - struct progress_bar progress; - - Printf("Restoring NTFS from image ...\n"); - - progress_init(&progress, p_counter, opt.std_out ? - sle64_to_cpu(image_hdr.nr_clusters) : - sle64_to_cpu(image_hdr.inuse), - 100); - - while (pos < sle64_to_cpu(image_hdr.nr_clusters)) { - if (read_all(&fd_in, &cmd, sizeof(cmd)) == -1) - perr_exit("read_all"); - - if (cmd == 0) { - if (read_all(&fd_in, &count, sizeof(count)) == -1) - perr_exit("read_all"); - if (!image_is_host_endian) - count = sle64_to_cpu(count); - if (opt.std_out) - write_empty_clusters(csize, count, - &progress, &p_counter); - else { - if (lseek(fd_out, count * csize, SEEK_CUR) == - (off_t)-1) - perr_exit("restore_image: lseek"); - } - pos += count; - } else if (cmd == 1) { - copy_cluster(0, 0); - pos++; - progress_update(&progress, ++p_counter); - } else - err_exit("Invalid command code in image\n"); - } -} - -static void wipe_index_entry_timestams(INDEX_ENTRY *e) -{ - s64 timestamp = utc2ntfs(0); - - /* FIXME: can fall into infinite loop if corrupted */ - while (!(e->flags & INDEX_ENTRY_END)) { - - e->key.file_name.creation_time = timestamp; - e->key.file_name.last_data_change_time = timestamp; - e->key.file_name.last_mft_change_time = timestamp; - e->key.file_name.last_access_time = timestamp; - - wiped_timestamp_data += 32; - - e = (INDEX_ENTRY *)((u8 *)e + le16_to_cpu(e->length)); - } -} - -static void wipe_index_allocation_timestamps(ntfs_inode *ni, ATTR_RECORD *attr) -{ - INDEX_ALLOCATION *indexa, *tmp_indexa; - INDEX_ENTRY *entry; - INDEX_ROOT *indexr; - u8 *bitmap, *byte; - int bit; - ntfs_attr *na; - ntfschar *name; - u32 name_len; - - indexr = ntfs_index_root_get(ni, attr); - if (!indexr) { - perr_printf("Failed to read $INDEX_ROOT attribute of inode " - "%lld", ni->mft_no); - return; - } - - if (indexr->type != AT_FILE_NAME) - goto out_indexr; - - name = (ntfschar *)((u8 *)attr + le16_to_cpu(attr->name_offset)); - name_len = attr->name_length; - - byte = bitmap = ntfs_attr_readall(ni, AT_BITMAP, name, name_len, NULL); - if (!byte) { - perr_printf("Failed to read $BITMAP attribute"); - goto out_indexr; - } - - na = ntfs_attr_open(ni, AT_INDEX_ALLOCATION, name, name_len); - if (!na) { - perr_printf("Failed to open $INDEX_ALLOCATION attribute"); - goto out_bitmap; - } - - if (!na->data_size) - goto out_na; - - tmp_indexa = indexa = ntfs_malloc(na->data_size); - if (!tmp_indexa) - goto out_na; - - if (ntfs_attr_pread(na, 0, na->data_size, indexa) != na->data_size) { - perr_printf("Failed to read $INDEX_ALLOCATION attribute"); - goto out_indexa; - } - - bit = 0; - while ((u8 *)tmp_indexa < (u8 *)indexa + na->data_size) { - if (*byte & (1 << bit)) { - if (ntfs_mst_post_read_fixup((NTFS_RECORD *)tmp_indexa, - le32_to_cpu( - indexr->index_block_size))) { - perr_printf("Damaged INDX record"); - goto out_indexa; - } - entry = (INDEX_ENTRY *)((u8 *)tmp_indexa + le32_to_cpu( - tmp_indexa->index.entries_offset) + 0x18); - - wipe_index_entry_timestams(entry); - - if (ntfs_mft_usn_dec((MFT_RECORD *)tmp_indexa)) - perr_exit("ntfs_mft_usn_dec"); - - if (ntfs_mst_pre_write_fixup((NTFS_RECORD *)tmp_indexa, - le32_to_cpu( - indexr->index_block_size))) { - perr_printf("INDX write fixup failed"); - goto out_indexa; - } - } - tmp_indexa = (INDEX_ALLOCATION *)((u8 *)tmp_indexa + - le32_to_cpu(indexr->index_block_size)); - bit++; - if (bit > 7) { - bit = 0; - byte++; - } - } - - if (ntfs_rl_pwrite(vol, na->rl, 0, na->data_size, indexa) != na->data_size) - perr_printf("ntfs_rl_pwrite failed for inode %lld", ni->mft_no); -out_indexa: - free(indexa); -out_na: - ntfs_attr_close(na); -out_bitmap: - free(bitmap); -out_indexr: - free(indexr); -} - -static void wipe_index_root_timestamps(ATTR_RECORD *attr, s64 timestamp) -{ - INDEX_ENTRY *entry; - INDEX_ROOT *iroot; - - iroot = (INDEX_ROOT *)((u8 *)attr + le16_to_cpu(attr->u.res.value_offset)); - entry = (INDEX_ENTRY *)((u8 *)iroot + - le32_to_cpu(iroot->index.entries_offset) + 0x10); - - while (!(entry->flags & INDEX_ENTRY_END)) { - - if (iroot->type == AT_FILE_NAME) { - - entry->key.file_name.creation_time = timestamp; - entry->key.file_name.last_access_time = timestamp; - entry->key.file_name.last_data_change_time = timestamp; - entry->key.file_name.last_mft_change_time = timestamp; - - wiped_timestamp_data += 32; - - } else if (ntfs_names_are_equal(NTFS_INDEX_Q, - sizeof(NTFS_INDEX_Q) / 2 - 1, - (ntfschar *)((char *)attr + - le16_to_cpu(attr->name_offset)), - attr->name_length, 0, NULL, 0)) { - - QUOTA_CONTROL_ENTRY *quota_q; - - quota_q = (QUOTA_CONTROL_ENTRY *)((u8 *)entry + - le16_to_cpu(entry->u.s.data_offset)); - /* - * FIXME: no guarantee it's indeed /$Extend/$Quota:$Q. - * For now, as a minimal safeguard, we check only for - * quota version 2 ... - */ - if (le32_to_cpu(quota_q->version) == 2) { - quota_q->change_time = timestamp; - wiped_timestamp_data += 4; - } - } - - entry = (INDEX_ENTRY*)((u8*)entry + le16_to_cpu(entry->length)); - } -} - -#define WIPE_TIMESTAMPS(atype, attr, timestamp) \ -do { \ - atype *ats; \ - ats = (atype *)((char *)(attr) + le16_to_cpu((attr)->u.res.value_offset)); \ - \ - ats->creation_time = (timestamp); \ - ats->last_data_change_time = (timestamp); \ - ats->last_mft_change_time= (timestamp); \ - ats->last_access_time = (timestamp); \ - \ - wiped_timestamp_data += 32; \ - \ -} while (0) - -static void wipe_timestamps(ntfs_walk_clusters_ctx *image) -{ - ATTR_RECORD *a = image->ctx->attr; - s64 timestamp = utc2ntfs(0); - - if (a->type == AT_FILE_NAME) - WIPE_TIMESTAMPS(FILE_NAME_ATTR, a, timestamp); - - else if (a->type == AT_STANDARD_INFORMATION) - WIPE_TIMESTAMPS(STANDARD_INFORMATION, a, timestamp); - - else if (a->type == AT_INDEX_ROOT) - wipe_index_root_timestamps(a, timestamp); -} - -static void wipe_resident_data(ntfs_walk_clusters_ctx *image) -{ - ATTR_RECORD *a; - u32 i; - int n = 0; - u8 *p; - - a = image->ctx->attr; - p = (u8*)a + le16_to_cpu(a->u.res.value_offset); - - if (image->ni->mft_no <= LAST_METADATA_INODE) - return; - - if (a->type != AT_DATA) - return; - - for (i = 0; i < le32_to_cpu(a->u.res.value_length); i++) { - if (p[i]) { - p[i] = 0; - n++; - } - } - - wiped_resident_data += n; -} - -static void clone_logfile_parts(ntfs_walk_clusters_ctx *image, runlist *rl) -{ - s64 offset = 0, lcn, vcn; - - while (1) { - - vcn = offset / image->ni->vol->cluster_size; - lcn = ntfs_rl_vcn_to_lcn(rl, vcn); - if (lcn < 0) - break; - - lseek_to_cluster(lcn); - copy_cluster(opt.rescue, lcn); - - if (offset == 0) - offset = NTFS_BLOCK_SIZE >> 1; - else - offset <<= 1; - } -} - -static void walk_runs(struct ntfs_walk_cluster *walk) -{ - int i, j; - runlist *rl; - ATTR_RECORD *a; - ntfs_attr_search_ctx *ctx; - - ctx = walk->image->ctx; - a = ctx->attr; - - if (!a->non_resident) { - if (wipe) { - wipe_resident_data(walk->image); - wipe_timestamps(walk->image); - } - return; - } - - if (wipe && walk->image->ctx->attr->type == AT_INDEX_ALLOCATION) - wipe_index_allocation_timestamps(walk->image->ni, a); - - if (!(rl = ntfs_mapping_pairs_decompress(vol, a, NULL))) - perr_exit("ntfs_decompress_mapping_pairs"); - - for (i = 0; rl[i].length; i++) { - s64 lcn = rl[i].lcn; - s64 lcn_length = rl[i].length; - - if (lcn == LCN_HOLE || lcn == LCN_RL_NOT_MAPPED) - continue; - - /* FIXME: ntfs_mapping_pairs_decompress should return error */ - if (lcn < 0 || lcn_length < 0) - err_exit("Corrupt runlist in inode %lld attr %x LCN " - "%llx length %llx\n", ctx->ntfs_ino->mft_no, - (unsigned int)le32_to_cpu(a->type), lcn, - lcn_length); - - if (!wipe) - dump_clusters(walk->image, rl + i); - - for (j = 0; j < lcn_length; j++) { - u64 k = (u64)lcn + j; - if (ntfs_bit_get_and_set(lcn_bitmap.bm, k, 1)) - err_exit("Cluster %llu referenced twice!\n" - "You didn't shutdown your Windows" - "properly?\n", (unsigned long long)k); - } - - walk->image->inuse += lcn_length; - } - if (!wipe && !opt.std_out && opt.metadata && - walk->image->ni->mft_no == FILE_LogFile && - walk->image->ctx->attr->type == AT_DATA) - clone_logfile_parts(walk->image, rl); - - free(rl); -} - - -static void walk_attributes(struct ntfs_walk_cluster *walk) -{ - ntfs_attr_search_ctx *ctx; - - if (!(ctx = ntfs_attr_get_search_ctx(walk->image->ni, NULL))) - perr_exit("ntfs_get_attr_search_ctx"); - - while (!ntfs_attrs_walk(ctx)) { - if (ctx->attr->type == AT_END) - break; - - walk->image->ctx = ctx; - walk_runs(walk); - } - - ntfs_attr_put_search_ctx(ctx); -} - - - -static void compare_bitmaps(struct bitmap *a) -{ - s64 i, pos, count; - int mismatch = 0; - u8 bm[NTFS_BUF_SIZE]; - - Printf("Accounting clusters ...\n"); - - pos = 0; - while (1) { - count = ntfs_attr_pread(vol->lcnbmp_na, pos, NTFS_BUF_SIZE, bm); - if (count == -1) - perr_exit("Couldn't get $Bitmap $DATA"); - - if (count == 0) { - if (a->size > pos) - err_exit("$Bitmap size is smaller than expected" - " (%lld != %lld)\n", a->size, pos); - break; - } - - for (i = 0; i < count; i++, pos++) { - s64 cl; /* current cluster */ - - if (a->size <= pos) - goto done; - - if (a->bm[pos] == bm[i]) - continue; - - for (cl = pos * 8; cl < (pos + 1) * 8; cl++) { - char bit; - - bit = ntfs_bit_get(a->bm, cl); - if (bit == ntfs_bit_get(bm, i * 8 + cl % 8)) - continue; - - if (opt.ignore_fs_check) { - lseek_to_cluster(cl); - copy_cluster(opt.rescue, cl); - } - - if (++mismatch > 10) - continue; - - Printf("Cluster accounting failed at %lld " - "(0x%llx): %s cluster in $Bitmap\n", - (long long)cl, (unsigned long long)cl, - bit ? "missing" : "extra"); - } - } - } -done: - if (mismatch) { - Printf("Totally %d cluster accounting mismatches.\n", mismatch); - if (opt.ignore_fs_check) { - Printf("WARNING: The NTFS inconsistency was overruled " - "by the --ignore-fs-check option.\n"); - return; - } - err_exit("Filesystem check failed! Windows wasn't shutdown " - "properly or inconsistent\nfilesystem. Please run " - "chkdsk /f on Windows then reboot it TWICE.\n"); - } -} - - -static int wipe_data(char *p, int pos, int len) -{ - int wiped = 0; - - for (p += pos; --len >= 0;) { - if (p[len]) { - p[len] = 0; - wiped++; - } - } - - return wiped; -} - -static void wipe_unused_mft_data(ntfs_inode *ni) -{ - int unused; - MFT_RECORD *m = ni->mrec; - - /* FIXME: broken MFTMirr update was fixed in libntfs, check if OK now */ - if (ni->mft_no <= LAST_METADATA_INODE) - return; - - unused = le32_to_cpu(m->bytes_allocated) - le32_to_cpu(m->bytes_in_use); - wiped_unused_mft_data += wipe_data((char *)m, - le32_to_cpu(m->bytes_in_use), unused); -} - -static void wipe_unused_mft(ntfs_inode *ni) -{ - int unused; - MFT_RECORD *m = ni->mrec; - - /* FIXME: broken MFTMirr update was fixed in libntfs, check if OK now */ - if (ni->mft_no <= LAST_METADATA_INODE) - return; - - unused = le32_to_cpu(m->bytes_in_use) - sizeof(MFT_RECORD); - wiped_unused_mft += wipe_data((char *)m, sizeof(MFT_RECORD), unused); -} - -static void mft_record_write_with_same_usn(ntfs_volume *volume, ntfs_inode *ni) -{ - if (ntfs_mft_usn_dec(ni->mrec)) - perr_exit("ntfs_mft_usn_dec"); - - if (ntfs_mft_record_write(volume, ni->mft_no, ni->mrec)) - perr_exit("ntfs_mft_record_write"); -} - -static void mft_inode_write_with_same_usn(ntfs_volume *volume, ntfs_inode *ni) -{ - s32 i; - - mft_record_write_with_same_usn(volume, ni); - - if (ni->nr_extents <= 0) - return; - - for (i = 0; i < ni->nr_extents; ++i) { - ntfs_inode *eni = ni->u.extent_nis[i]; - mft_record_write_with_same_usn(volume, eni); - } -} - -static int walk_clusters(ntfs_volume *volume, struct ntfs_walk_cluster *walk) -{ - s64 inode = 0; - s64 last_mft_rec; - ntfs_inode *ni; - struct progress_bar progress; - - Printf("Scanning volume ...\n"); - - last_mft_rec = (volume->mft_na->initialized_size >> - volume->mft_record_size_bits) - 1; - progress_init(&progress, inode, last_mft_rec, 100); - - for (; inode <= last_mft_rec; inode++) { - - int err, deleted_inode; - MFT_REF mref = (MFT_REF)inode; - - progress_update(&progress, inode); - - /* FIXME: Terrible kludge for libntfs not being able to return - a deleted MFT record as inode */ - ni = ntfs_calloc(sizeof(ntfs_inode)); - if (!ni) - perr_exit("walk_clusters"); - - ni->vol = volume; - - err = ntfs_file_record_read(volume, mref, &ni->mrec, NULL); - if (err == -1) { - free(ni); - continue; - } - - deleted_inode = !(ni->mrec->flags & MFT_RECORD_IN_USE); - - if (deleted_inode) { - - ni->mft_no = MREF(mref); - if (wipe) { - wipe_unused_mft(ni); - wipe_unused_mft_data(ni); - mft_record_write_with_same_usn(volume, ni); - } - } - - free(ni->mrec); - free(ni); - - if (deleted_inode) - continue; - - if ((ni = ntfs_inode_open(volume, mref)) == NULL) { - /* FIXME: continue only if it make sense, e.g. - MFT record not in use based on $MFT bitmap */ - if (errno == EIO || errno == ENOENT) - continue; - perr_exit("Reading inode %lld failed", inode); - } - - if (wipe) - nr_used_mft_records++; - - if (ni->mrec->base_mft_record) - goto out; - - walk->image->ni = ni; - walk_attributes(walk); -out: - if (wipe) { - wipe_unused_mft_data(ni); - mft_inode_write_with_same_usn(volume, ni); - } - - if (ntfs_inode_close(ni)) - perr_exit("ntfs_inode_close for inode %lld", inode); - } - - return 0; -} - - -/* - * $Bitmap can overlap the end of the volume. Any bits in this region - * must be set. This region also encompasses the backup boot sector. - */ -static void bitmap_file_data_fixup(s64 cluster, struct bitmap *bm) -{ - for (; cluster < bm->size << 3; cluster++) - ntfs_bit_set(bm->bm, (u64)cluster, 1); -} - - -/* - * Allocate a block of memory with one bit for each cluster of the disk. - * All the bits are set to 0, except those representing the region beyond the - * end of the disk. - */ -static void setup_lcn_bitmap(void) -{ - /* Determine lcn bitmap byte size and allocate it. */ - lcn_bitmap.size = rounded_up_division(vol->nr_clusters, 8); - - lcn_bitmap.bm = ntfs_calloc(lcn_bitmap.size); - if (!lcn_bitmap.bm) - perr_exit("Failed to allocate internal buffer"); - - bitmap_file_data_fixup(vol->nr_clusters, &lcn_bitmap); -} - - -static s64 volume_size(ntfs_volume *volume, s64 nr_clusters) -{ - return nr_clusters * volume->cluster_size; -} - - -static void print_volume_size(const char *str, s64 bytes) -{ - Printf("%s: %lld bytes (%lld MB)\n", str, (long long)bytes, - (long long)rounded_up_division(bytes, NTFS_MBYTE)); -} - - -static void print_disk_usage(const char *spacer, u32 cluster_size, - s64 nr_clusters, s64 inuse) -{ - s64 total, used; - - total = nr_clusters * cluster_size; - used = inuse * cluster_size; - - Printf("Space in use %s: %lld MB (%.1f%%) ", spacer, - (long long)rounded_up_division(used, NTFS_MBYTE), - 100.0 * ((float)used / total)); - - Printf("\n"); -} - -static void print_image_info(void) -{ - Printf("Ntfsclone image version: %d.%d\n", - image_hdr.major_ver, image_hdr.minor_ver); - Printf("Cluster size : %u bytes\n", - (unsigned)le32_to_cpu(image_hdr.cluster_size)); - print_volume_size("Image volume size ", - sle64_to_cpu(image_hdr.nr_clusters) * - le32_to_cpu(image_hdr.cluster_size)); - Printf("Image device size : %lld bytes\n", - sle64_to_cpu(image_hdr.device_size)); - print_disk_usage(" ", le32_to_cpu(image_hdr.cluster_size), - sle64_to_cpu(image_hdr.nr_clusters), - sle64_to_cpu(image_hdr.inuse)); - Printf("Offset to image data : %u (0x%x) bytes\n", - (unsigned)le32_to_cpu(image_hdr.offset_to_image_data), - (unsigned)le32_to_cpu(image_hdr.offset_to_image_data)); -} - -static void check_if_mounted(const char *device, unsigned long new_mntflag) -{ - unsigned long mntflag; - - if (ntfs_check_if_mounted(device, &mntflag)) - perr_exit("Failed to check '%s' mount state", device); - - if (mntflag & NTFS_MF_MOUNTED) { - if (!(mntflag & NTFS_MF_READONLY)) - err_exit("Device '%s' is mounted read-write. " - "You must 'umount' it first.\n", device); - if (!new_mntflag) - err_exit("Device '%s' is mounted. " - "You must 'umount' it first.\n", device); - } -} - -/** - * mount_volume - - * - * First perform some checks to determine if the volume is already mounted, or - * is dirty (Windows wasn't shutdown properly). If everything is OK, then mount - * the volume (load the metadata into memory). - */ -static void mount_volume(unsigned long new_mntflag) -{ - check_if_mounted(opt.volume, new_mntflag); - - if (!(vol = ntfs_mount(opt.volume, new_mntflag))) { - - int err = errno; - - perr_printf("Opening '%s' as NTFS failed", opt.volume); - if (err == EINVAL) { - Printf("Apparently device '%s' doesn't have a " - "valid NTFS. Maybe you selected\nthe whole " - "disk instead of a partition (e.g. /dev/hda, " - "not /dev/hda1)?\n", opt.volume); - } - exit(1); - } - - if (NVolWasDirty(vol)) - if (opt.force-- <= 0) - err_exit(dirty_volume_msg, opt.volume); - - if (NTFS_MAX_CLUSTER_SIZE < vol->cluster_size) - err_exit("Cluster size %u is too large!\n", - (unsigned int)vol->cluster_size); - - Printf("NTFS volume version: %d.%d\n", vol->major_ver, vol->minor_ver); - if (ntfs_version_is_supported(vol)) - perr_exit("Unknown NTFS version"); - - Printf("Cluster size : %u bytes\n", - (unsigned int)vol->cluster_size); - print_volume_size("Current volume size", - volume_size(vol, vol->nr_clusters)); -} - -static struct ntfs_walk_cluster backup_clusters = { NULL, NULL }; - -static int device_offset_valid(int fd, s64 ofs) -{ - char ch; - - if (lseek(fd, ofs, SEEK_SET) >= 0 && read(fd, &ch, 1) == 1) - return 0; - return -1; -} - -static s64 device_size_get(int fd) -{ - s64 high, low; -#ifdef BLKGETSIZE64 - { u64 size; - - if (ioctl(fd, BLKGETSIZE64, &size) >= 0) { - ntfs_log_debug("BLKGETSIZE64 nr bytes = %llu " - "(0x%llx).\n", (unsigned long long)size, - (unsigned long long)size); - return (s64)size; - } - } -#endif -#ifdef BLKGETSIZE - { unsigned long size; - - if (ioctl(fd, BLKGETSIZE, &size) >= 0) { - ntfs_log_debug("BLKGETSIZE nr 512 byte blocks = %lu " - "(0x%lx).\n", size, size); - return (s64)size * 512; - } - } -#endif -#ifdef FDGETPRM - { struct floppy_struct this_floppy; - - if (ioctl(fd, FDGETPRM, &this_floppy) >= 0) { - ntfs_log_debug("FDGETPRM nr 512 byte blocks = %lu " - "(0x%lx).\n", this_floppy.size, - this_floppy.size); - return (s64)this_floppy.size * 512; - } - } -#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; !device_offset_valid(fd, high); high <<= 1) - low = high; - while (low < high - 1LL) { - const s64 mid = (low + high) / 2; - - if (!device_offset_valid(fd, mid)) - low = mid; - else - high = mid; - } - lseek(fd, 0LL, SEEK_SET); - return (low + 1LL); -} - -static void fsync_clone(int fd) -{ - Printf("Syncing ...\n"); - if (fsync(fd) && errno != EINVAL) - perr_exit("fsync"); -} - -static void set_filesize(s64 filesize) -{ - -#ifdef __sun - - if (fstatvfs(fd_out, &opt.stfs) == -1) - Printf("WARNING: Couldn't get filesystem type: " - "%s\n", strerror(errno)); - - if (strcmp(opt.stfs.f_basetype, "pcfs") == 0) - Printf("WARNING: You're using PCFS, it does not support " - "sparse files so the next operation might take " - "a while. You should consider using the more " - "efficient --save-image option of ntfsclone. Use " - "the --restore-image option to restore the image.\n"); - - if (ftruncate(fd_out, filesize) == -1) { - int err = errno; - perr_printf("ftruncate failed for file '%s'", opt.output); - Printf("Destination filesystem type is %s\n", - opt.stfs.f_basetype); - if (err == EFBIG || (err == EINVAL && filesize > 0)) - Printf("Your system or the destination filesystem " - "doesn't support large files.\n"); - exit(1); - } - -#else /* !defined(__sun) */ - - long fs_type = 0; /* Unknown filesystem type */ - - if (fstatfs(fd_out, &opt.stfs) == -1) - Printf("WARNING: Couldn't get filesystem type: " - "%s\n", strerror(errno)); - else - fs_type = opt.stfs.f_type; - - if (fs_type == 0x52654973) - Printf("WARNING: You're using ReiserFS, it has very poor " - "performance creating\nlarge sparse files. The next " - "operation might take a very long time!\n" - "Creating sparse output file ...\n"); - else if (fs_type == 0x517b) - Printf("WARNING: You're using SMBFS and if the remote share " - "isn't Samba but a Windows\ncomputer then the clone " - "operation will be very inefficient and may fail!\n"); - - if (ftruncate(fd_out, filesize) == -1) { - int err = errno; - perr_printf("ftruncate failed for file '%s'", opt.output); - if (fs_type) - Printf("Destination filesystem type is 0x%lx.\n", - (unsigned long)fs_type); - if (err == E2BIG) { - Printf("Your system or the destination filesystem " - "doesn't support large files.\n"); - if (fs_type == 0x517b) { - Printf("SMBFS needs minimum Linux kernel " - "version 2.4.25 and\n the 'lfs' option" - "\nfor smbmount to have large " - "file support.\n"); - } - } else if (err == EPERM) { - Printf("Apparently the destination filesystem doesn't " - "support sparse files.\nYou can overcome this " - "by using the more efficient --save-image " - "option\nof ntfsclone. Use the --restore-image " - "option to restore the image.\n"); - } - exit(1); - } - -#endif /* defined(__sun) */ -} - -static s64 open_image(void) -{ - if (strcmp(opt.volume, "-") == 0) { - if ((fd_in = fileno(stdin)) == -1) - perr_exit("fileno for stdout failed"); - } else { - if ((fd_in = open(opt.volume, O_RDONLY)) == -1) - perr_exit("failed to open image"); - } - if (read_all(&fd_in, &image_hdr, NTFSCLONE_IMG_HEADER_SIZE_OLD) == -1) - perr_exit("read_all"); - if (memcmp(image_hdr.magic, IMAGE_MAGIC, IMAGE_MAGIC_SIZE) != 0) - err_exit("Input file is not an image! (invalid magic)\n"); - if (image_hdr.major_ver < NTFSCLONE_IMG_VER_MAJOR_ENDIANNESS_SAFE) { - image_hdr.major_ver = NTFSCLONE_IMG_VER_MAJOR; - image_hdr.minor_ver = NTFSCLONE_IMG_VER_MINOR; -#if (__BYTE_ORDER == __BIG_ENDIAN) - Printf("Old image format detected. If the image was created " - "on a little endian architecture it will not " - "work. Use a more recent version of " - "ntfsclone to recreate the image.\n"); - image_hdr.cluster_size = cpu_to_le32(image_hdr.cluster_size); - image_hdr.device_size = cpu_to_sle64(image_hdr.device_size); - image_hdr.nr_clusters = cpu_to_sle64(image_hdr.nr_clusters); - image_hdr.inuse = cpu_to_sle64(image_hdr.inuse); -#endif - image_hdr.offset_to_image_data = - const_cpu_to_le32((sizeof(image_hdr) + 7) & ~7); - image_is_host_endian = TRUE; - } else { -#ifdef __sun - u32 offset_to_image_data; -#else - typeof(image_hdr.offset_to_image_data) offset_to_image_data; -#endif - int delta; - - if (image_hdr.major_ver > NTFSCLONE_IMG_VER_MAJOR) - err_exit("Do not know how to handle image format " - "version %d.%d. Please obtain a " - "newer version of ntfsclone.\n", - image_hdr.major_ver, - image_hdr.minor_ver); - /* Read the image header data offset. */ - if (read_all(&fd_in, &offset_to_image_data, - sizeof(offset_to_image_data)) == -1) - perr_exit("read_all"); - image_hdr.offset_to_image_data = - le32_to_cpu(offset_to_image_data); - /* - * Read any fields from the header that we have not read yet so - * that the input stream is positioned correctly. This means - * we can support future minor versions that just extend the - * header in a backwards compatible way. - */ - delta = offset_to_image_data - (NTFSCLONE_IMG_HEADER_SIZE_OLD + - sizeof(image_hdr.offset_to_image_data)); - if (delta > 0) { - char *dummy_buf; - - dummy_buf = malloc(delta); - if (!dummy_buf) - perr_exit("malloc dummy_buffer"); - if (read_all(&fd_in, dummy_buf, delta) == -1) - perr_exit("read_all"); - } - } - return sle64_to_cpu(image_hdr.device_size); -} - -static s64 open_volume(void) -{ - s64 device_size; - - mount_volume(NTFS_MNT_RDONLY); - - device_size = ntfs_device_size_get(vol->u.dev, 1); - if (device_size <= 0) - err_exit("Couldn't get device size (%lld)!\n", device_size); - - print_volume_size("Current device size", device_size); - - if (device_size < vol->nr_clusters * vol->cluster_size) - err_exit("Current NTFS volume size is bigger than the device " - "size (%lld)!\nCorrupt partition table or incorrect " - "device partitioning?\n", device_size); - - return device_size; -} - -static void initialise_image_hdr(s64 device_size, s64 inuse) -{ - memcpy(image_hdr.magic, IMAGE_MAGIC, IMAGE_MAGIC_SIZE); - image_hdr.major_ver = NTFSCLONE_IMG_VER_MAJOR; - image_hdr.minor_ver = NTFSCLONE_IMG_VER_MINOR; - image_hdr.cluster_size = cpu_to_le32(vol->cluster_size); - image_hdr.device_size = cpu_to_sle64(device_size); - image_hdr.nr_clusters = cpu_to_sle64(vol->nr_clusters); - image_hdr.inuse = cpu_to_sle64(inuse); - image_hdr.offset_to_image_data = cpu_to_le32((sizeof(image_hdr) + 7) & - ~7); -} - -static void check_output_device(s64 input_size) -{ - if (opt.blkdev_out) { - s64 dest_size = device_size_get(fd_out); - if (dest_size < input_size) - err_exit("Output device is too small (%lld) to fit the " - "NTFS image (%lld).\n", dest_size, input_size); - - check_if_mounted(opt.output, 0); - } else - set_filesize(input_size); -} - -static ntfs_attr_search_ctx *attr_get_search_ctx(ntfs_inode *ni) -{ - ntfs_attr_search_ctx *ret; - - if ((ret = ntfs_attr_get_search_ctx(ni, NULL)) == NULL) - perr_printf("ntfs_attr_get_search_ctx"); - - return ret; -} - -/** - * lookup_data_attr - * - * Find the $DATA attribute (with or without a name) for the given ntfs inode. - */ -static ntfs_attr_search_ctx *lookup_data_attr(ntfs_inode *ni, const char *aname) -{ - ntfs_attr_search_ctx *ctx; - ntfschar *ustr; - int len = 0; - - if ((ctx = attr_get_search_ctx(ni)) == NULL) - return NULL; - - if ((ustr = ntfs_str2ucs(aname, &len)) == NULL) { - perr_printf("Couldn't convert '%s' to Unicode", aname); - goto error_out; - } - - if (ntfs_attr_lookup(AT_DATA, ustr, len, 0, 0, NULL, 0, ctx)) { - perr_printf("ntfs_attr_lookup"); - goto error_out; - } - ntfs_ucsfree(ustr); - return ctx; -error_out: - ntfs_attr_put_search_ctx(ctx); - return NULL; -} - -static void ignore_bad_clusters(ntfs_walk_clusters_ctx *image) -{ - ntfs_inode *ni; - ntfs_attr_search_ctx *ctx = NULL; - runlist *rl, *rl_bad; - s64 nr_bad_clusters = 0; - - if (!(ni = ntfs_inode_open(vol, FILE_BadClus))) - perr_exit("ntfs_open_inode"); - - if ((ctx = lookup_data_attr(ni, "$Bad")) == NULL) - exit(1); - - if (!(rl_bad = ntfs_mapping_pairs_decompress(vol, ctx->attr, NULL))) - perr_exit("ntfs_mapping_pairs_decompress"); - - for (rl = rl_bad; rl->length; rl++) { - s64 lcn = rl->lcn; - - if (lcn == LCN_HOLE || lcn < 0) - continue; - - for (; lcn < rl->lcn + rl->length; lcn++, nr_bad_clusters++) { - if (ntfs_bit_get_and_set(lcn_bitmap.bm, lcn, 0)) - image->inuse--; - } - } - if (nr_bad_clusters) - Printf("WARNING: The disk has %lld or more bad sectors" - " (hardware faults).\n", nr_bad_clusters); - free(rl_bad); - - ntfs_attr_put_search_ctx(ctx); - if (ntfs_inode_close(ni)) - perr_exit("ntfs_inode_close failed for $BadClus"); -} - -static void check_dest_free_space(u64 src_bytes) -{ - u64 dest_bytes; - struct statvfs stvfs; - struct stat st; - - if (opt.metadata || opt.blkdev_out || opt.std_out) - return; - /* - * TODO: save_image needs a bit more space than src_bytes - * due to the free space encoding overhead. - */ - if (fstatvfs(fd_out, &stvfs) == -1) { - Printf("WARNING: Unknown free space on the destination: %s\n", - strerror(errno)); - return; - } - - /* If file is a FIFO then there is no point in checking the size. */ - if (!fstat(fd_out, &st)) { - if (S_ISFIFO(st.st_mode)) - return; - } else - Printf("WARNING: fstat failed: %s\n", strerror(errno)); - - dest_bytes = (u64)stvfs.f_frsize * stvfs.f_bfree; - if (!dest_bytes) - dest_bytes = (u64)stvfs.f_bsize * stvfs.f_bfree; - - if (dest_bytes < src_bytes) - err_exit("Destination doesn't have enough free space: " - "%llu MB < %llu MB\n", - rounded_up_division(dest_bytes, NTFS_MBYTE), - rounded_up_division(src_bytes, NTFS_MBYTE)); -} - -int main(int argc, char **argv) -{ - ntfs_walk_clusters_ctx image; - s64 device_size; /* input device size in bytes */ - s64 ntfs_size; - unsigned int wiped_total = 0; - - /* print to stderr, stdout can be an NTFS image ... */ - fprintf(stderr, "%s v%s (libntfs %s)\n", EXEC_NAME, VERSION, - ntfs_libntfs_version()); - msg_out = stderr; - - parse_options(argc, argv); - - utils_set_locale(); - - if (opt.restore_image) { - device_size = open_image(); - ntfs_size = sle64_to_cpu(image_hdr.nr_clusters) * - le32_to_cpu(image_hdr.cluster_size); - } else { - device_size = open_volume(); - ntfs_size = vol->nr_clusters * vol->cluster_size; - } - // FIXME: This needs to be the cluster size... - ntfs_size += 512; /* add backup boot sector */ - - if (opt.std_out) { - if ((fd_out = fileno(stdout)) == -1) - perr_exit("fileno for stdout failed"); - } else { - /* device_size_get() might need to read() */ - int flags = O_RDWR; - - if (!opt.blkdev_out) { - flags |= O_CREAT | O_TRUNC; - if (!opt.overwrite) - flags |= O_EXCL; - } - - if ((fd_out = open(opt.output, flags, S_IRUSR | S_IWUSR)) == -1) - perr_exit("Opening file '%s' failed", opt.output); - - if (!opt.save_image) - check_output_device(ntfs_size); - } - - if (opt.restore_image) { - print_image_info(); - restore_image(); - fsync_clone(fd_out); - exit(0); - } - - setup_lcn_bitmap(); - memset(&image, 0, sizeof(image)); - backup_clusters.image = ℑ - - walk_clusters(vol, &backup_clusters); - compare_bitmaps(&lcn_bitmap); - print_disk_usage("", vol->cluster_size, vol->nr_clusters, image.inuse); - - check_dest_free_space(vol->cluster_size * image.inuse); - - ignore_bad_clusters(&image); - - if (opt.save_image) - initialise_image_hdr(device_size, image.inuse); - - /* FIXME: save backup boot sector */ - - if (opt.std_out || !opt.metadata) { - s64 nr_clusters_to_save = image.inuse; - if (opt.std_out && !opt.save_image) - nr_clusters_to_save = vol->nr_clusters; - - clone_ntfs(nr_clusters_to_save); - fsync_clone(fd_out); - exit(0); - } - - wipe = 1; - opt.volume = opt.output; - /* 'force' again mount for dirty volumes (e.g. after resize). - FIXME: use mount flags to avoid potential side-effects in future */ - opt.force++; - mount_volume(0); - - free(lcn_bitmap.bm); - setup_lcn_bitmap(); - memset(&image, 0, sizeof(image)); - backup_clusters.image = ℑ - - walk_clusters(vol, &backup_clusters); - - Printf("Num of MFT records = %10lld\n", - (long long)vol->mft_na->initialized_size >> - vol->mft_record_size_bits); - Printf("Num of used MFT records = %10u\n", nr_used_mft_records); - - Printf("Wiped unused MFT data = %10u\n", wiped_unused_mft_data); - Printf("Wiped deleted MFT data = %10u\n", wiped_unused_mft); - Printf("Wiped resident user data = %10u\n", wiped_resident_data); - Printf("Wiped timestamp data = %10u\n", wiped_timestamp_data); - - wiped_total += wiped_unused_mft_data; - wiped_total += wiped_unused_mft; - wiped_total += wiped_resident_data; - wiped_total += wiped_timestamp_data; - Printf("Wiped totally = %10u\n", wiped_total); - - fsync_clone(fd_out); - exit(0); -} diff --git a/usr/src/cmd/ntfsprogs/ntfscluster.c b/usr/src/cmd/ntfsprogs/ntfscluster.c deleted file mode 100644 index 64ee4af130..0000000000 --- a/usr/src/cmd/ntfsprogs/ntfscluster.c +++ /dev/null @@ -1,565 +0,0 @@ -/** - * ntfscluster - Part of the Linux-NTFS project. - * - * Copyright (c) 2002-2003 Richard Russon - * Copyright (c) 2005 Anton Altaparmakov - * Copyright (c) 2005-2006 Szabolcs Szakacsits - * - * This utility will locate the owner of any given sector or cluster. - * - * 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 Linux-NTFS - * 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_STDIO_H -#include <stdio.h> -#endif -#ifdef HAVE_GETOPT_H -#include <getopt.h> -#endif -#ifdef HAVE_STDLIB_H -#include <stdlib.h> -#endif -#ifdef HAVE_STRING_H -#include <string.h> -#endif -#ifdef HAVE_LIMITS_H -#include <limits.h> -#endif - -#include "compat.h" -#include "ntfscluster.h" -#include "types.h" -#include "attrib.h" -#include "utils.h" -#include "volume.h" -#include "debug.h" -#include "dir.h" -#include "cluster.h" -#include "version.h" -#include "logging.h" - -static const char *EXEC_NAME = "ntfscluster"; -static struct options opts; - -/** - * version - Print version information about the program - * - * Print a copyright statement and a brief description of the program. - * - * Return: none - */ -static void version(void) -{ - ntfs_log_info("\n%s v%s (libntfs %s) - Find the owner of any given sector or " - "cluster.\n\n", EXEC_NAME, VERSION, - ntfs_libntfs_version()); - ntfs_log_info("Copyright (c) 2002-2003 Richard Russon\n"); - ntfs_log_info("Copyright (c) 2005 Anton Altaparmakov\n"); - ntfs_log_info("Copyright (c) 2005-2006 Szabolcs Szakacsits\n"); - ntfs_log_info("\n%s\n%s%s\n", ntfs_gpl, ntfs_bugs, ntfs_home); -} - -/** - * usage - Print a list of the parameters to the program - * - * Print a list of the parameters and options for the program. - * - * Return: none - */ -static void usage(void) -{ - ntfs_log_info("\nUsage: %s [options] device\n" - " -i, --info Print information about the volume (default)\n" - "\n" - " -c, --cluster RANGE Look for objects in this range of clusters\n" - " -s, --sector RANGE Look for objects in this range of sectors\n" - " -I, --inode NUM Show information about this inode\n" - " -F, --filename NAME Show information about this file\n" - /* " -l, --last Find the last file on the volume\n" */ - "\n" - " -f, --force Use less caution\n" - " -q, --quiet Less output\n" - " -v, --verbose More output\n" - " -V, --version Version information\n" - " -h, --help Print this help\n\n", - EXEC_NAME); - ntfs_log_info("%s%s\n", ntfs_bugs, ntfs_home); -} - -/** - * parse_options - Read and validate the programs command line - * - * Read the command line, verify the syntax and parse the options. - * This function is very long, but quite simple. - * - * Return: 1 Success - * 0 Error, one or more problems - */ -static int parse_options(int argc, char **argv) -{ - static const char *sopt = "-c:F:fh?I:ilqs:vV"; - static const struct option lopt[] = { - { "cluster", required_argument, NULL, 'c' }, - { "filename", required_argument, NULL, 'F' }, - { "force", no_argument, NULL, 'f' }, - { "help", no_argument, NULL, 'h' }, - { "info", no_argument, NULL, 'i' }, - { "inode", required_argument, NULL, 'I' }, - { "last", no_argument, NULL, 'l' }, - { "quiet", no_argument, NULL, 'q' }, - { "sector", required_argument, NULL, 's' }, - { "verbose", no_argument, NULL, 'v' }, - { "version", no_argument, NULL, 'V' }, - { NULL, 0, NULL, 0 } - }; - - int c = -1; - int err = 0; - int ver = 0; - int help = 0; - int levels = 0; - char *end = NULL; - - opterr = 0; /* We'll handle the errors, thank you. */ - - opts.action = act_none; - opts.range_begin = -1; - opts.range_end = -1; - - while ((c = getopt_long(argc, argv, sopt, lopt, NULL)) != -1) { - switch (c) { - case 1: /* A non-option argument */ - if (!opts.device) { - opts.device = argv[optind-1]; - } else { - opts.device = NULL; - err++; - } - break; - - case 'c': - if ((opts.action == act_none) && - (utils_parse_range(optarg, &opts.range_begin, &opts.range_end, FALSE))) - opts.action = act_cluster; - else - opts.action = act_error; - break; - case 'F': - if (opts.action == act_none) { - opts.action = act_file; - opts.filename = optarg; - } else { - opts.action = act_error; - } - break; - case 'f': - opts.force++; - break; - case 'h': - case '?': - if (strncmp (argv[optind-1], "--log-", 6) == 0) { - if (!ntfs_log_parse_option (argv[optind-1])) - err++; - break; - } - help++; - break; - case 'I': - if (opts.action == act_none) { - opts.action = act_inode; - opts.inode = strtol(optarg, &end, 0); - if (end && *end) - err++; - } else { - opts.action = act_error; - } - break; - case 'i': - if (opts.action == act_none) - opts.action = act_info; - else - opts.action = act_error; - break; - case 'l': - if (opts.action == act_none) - opts.action = act_last; - else - opts.action = act_error; - break; - case 'q': - opts.quiet++; - ntfs_log_clear_levels(NTFS_LOG_LEVEL_QUIET); - break; - case 's': - if ((opts.action == act_none) && - (utils_parse_range(optarg, &opts.range_begin, &opts.range_end, FALSE))) - opts.action = act_sector; - else - opts.action = act_error; - break; - case 'v': - opts.verbose++; - ntfs_log_set_levels(NTFS_LOG_LEVEL_VERBOSE); - break; - case 'V': - ver++; - break; - default: - if ((optopt == 'c') || (optopt == 's')) - ntfs_log_error("Option '%s' requires an argument.\n", argv[optind-1]); - else - ntfs_log_error("Unknown option '%s'.\n", argv[optind-1]); - err++; - break; - } - } - - /* Make sure we're in sync with the log levels */ - levels = ntfs_log_get_levels(); - if (levels & NTFS_LOG_LEVEL_VERBOSE) - opts.verbose++; - if (!(levels & NTFS_LOG_LEVEL_QUIET)) - opts.quiet++; - - if (help || ver) { - opts.quiet = 0; - } else { - if (opts.action == act_none) - opts.action = act_info; - if (opts.action == act_info) - opts.quiet = 0; - - if (opts.device == NULL) { - if (argc > 1) - ntfs_log_error("You must specify exactly one device.\n"); - err++; - } - - if (opts.quiet && opts.verbose) { - ntfs_log_error("You may not use --quiet and --verbose at the same time.\n"); - err++; - } - - if (opts.action == act_error) { - ntfs_log_error("You may only specify one action: --info, --cluster, --sector or --last.\n"); - err++; - } else if (opts.range_begin > opts.range_end) { - ntfs_log_error("The range must be in ascending order.\n"); - err++; - } - } - - if (ver) - version(); - if (help || err) - usage(); - - return (!err && !help && !ver); -} - - -/** - * info - */ -static int info(ntfs_volume *vol) -{ - u64 a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u; - int cb, sb, cps; - u64 uc = 0, mc = 0, fc = 0; - - struct mft_search_ctx *m_ctx; - ntfs_attr_search_ctx *a_ctx; - runlist_element *rl; - ATTR_RECORD *rec; - int z; - int inuse = 0; - - m_ctx = mft_get_search_ctx(vol); - m_ctx->flags_search = FEMR_IN_USE | FEMR_METADATA | FEMR_BASE_RECORD | FEMR_NOT_BASE_RECORD; - while (mft_next_record(m_ctx) == 0) { - - if (!(m_ctx->flags_match & FEMR_IN_USE)) - continue; - - inuse++; - - a_ctx = ntfs_attr_get_search_ctx(m_ctx->inode, NULL); - - while ((rec = find_attribute(AT_UNUSED, a_ctx))) { - - if (!rec->non_resident) - continue; - - rl = ntfs_mapping_pairs_decompress(vol, rec, NULL); - - for (z = 0; rl[z].length > 0; z++) - { - if (rl[z].lcn >= 0) { - if (m_ctx->flags_match & FEMR_METADATA) - mc += rl[z].length; - else - uc += rl[z].length; - } - - } - - free(rl); - } - - ntfs_attr_put_search_ctx(a_ctx); - } - mft_put_search_ctx(m_ctx); - - cb = vol->cluster_size_bits; - sb = vol->sector_size_bits; - cps = cb - sb; - - fc = vol->nr_clusters-mc-uc; - fc <<= cb; - mc <<= cb; - uc <<= cb; - - a = vol->sector_size; - b = vol->cluster_size; - c = 1 << cps; - d = vol->nr_clusters << cb; - e = vol->nr_clusters; - f = vol->nr_clusters >> cps; - g = vol->mft_na->initialized_size >> vol->mft_record_size_bits; - h = inuse; - i = h * 100 / g; - j = fc; - k = fc >> sb; - l = fc >> cb; - m = fc * 100 / b / e; - n = uc; - o = uc >> sb; - p = uc >> cb; - q = uc * 100 / b / e; - r = mc; - s = mc >> sb; - t = mc >> cb; - u = mc * 100 / b / e; - - ntfs_log_info("bytes per sector : %llu\n", (unsigned long long)a); - ntfs_log_info("bytes per cluster : %llu\n", (unsigned long long)b); - ntfs_log_info("sectors per cluster : %llu\n", (unsigned long long)c); - ntfs_log_info("bytes per volume : %llu\n", (unsigned long long)d); - ntfs_log_info("sectors per volume : %llu\n", (unsigned long long)e); - ntfs_log_info("clusters per volume : %llu\n", (unsigned long long)f); - ntfs_log_info("initialized mft records : %llu\n", (unsigned long long)g); - ntfs_log_info("mft records in use : %llu\n", (unsigned long long)h); - ntfs_log_info("mft records percentage : %llu\n", (unsigned long long)i); - ntfs_log_info("bytes of free space : %llu\n", (unsigned long long)j); - ntfs_log_info("sectors of free space : %llu\n", (unsigned long long)k); - ntfs_log_info("clusters of free space : %llu\n", (unsigned long long)l); - ntfs_log_info("percentage free space : %llu\n", (unsigned long long)m); - ntfs_log_info("bytes of user data : %llu\n", (unsigned long long)n); - ntfs_log_info("sectors of user data : %llu\n", (unsigned long long)o); - ntfs_log_info("clusters of user data : %llu\n", (unsigned long long)p); - ntfs_log_info("percentage user data : %llu\n", (unsigned long long)q); - ntfs_log_info("bytes of metadata : %llu\n", (unsigned long long)r); - ntfs_log_info("sectors of metadata : %llu\n", (unsigned long long)s); - ntfs_log_info("clusters of metadata : %llu\n", (unsigned long long)t); - ntfs_log_info("percentage metadata : %llu\n", (unsigned long long)u); - - return 0; -} - -/** - * dump_file - */ -static int dump_file(ntfs_volume *vol, ntfs_inode *ino) -{ - char buffer[1024]; - ntfs_attr_search_ctx *ctx; - ATTR_RECORD *rec; - int i; - runlist *runs; - - utils_inode_get_name(ino, buffer, sizeof(buffer)); - - ntfs_log_info("Dump: %s\n", buffer); - - ctx = ntfs_attr_get_search_ctx(ino, NULL); - - while ((rec = find_attribute(AT_UNUSED, ctx))) { - ntfs_log_info(" 0x%02x - ", rec->type); - if (rec->non_resident) { - ntfs_log_info("non-resident\n"); - runs = ntfs_mapping_pairs_decompress(vol, rec, NULL); - if (runs) { - ntfs_log_info(" VCN LCN Length\n"); - for (i = 0; runs[i].length > 0; i++) { - ntfs_log_info(" %8lld %8lld %8lld\n", - (long long)runs[i].vcn, - (long long)runs[i].lcn, - (long long) - runs[i].length); - } - free(runs); - } - } else { - ntfs_log_info("resident\n"); - } - } - - ntfs_attr_put_search_ctx(ctx); - return 0; -} - -/** - * print_match - */ -static int print_match(ntfs_inode *ino, ATTR_RECORD *attr, - runlist_element *run, void *data __attribute__((unused))) -{ - char *buffer; - - if (!ino || !attr || !run) - return 1; - - buffer = malloc(MAX_PATH); - if (!buffer) { - ntfs_log_error("!buffer\n"); - return 1; - } - - utils_inode_get_name(ino, buffer, MAX_PATH); - ntfs_log_info("Inode %llu %s", (unsigned long long)ino->mft_no, buffer); - - utils_attr_get_name(ino->vol, attr, buffer, MAX_PATH); - ntfs_log_info("/%s\n", buffer); - - free(buffer); - return 0; -} - -/** - * find_last - */ -static int find_last(ntfs_inode *ino, ATTR_RECORD *attr, runlist_element *run, - void *data) -{ - struct match *m; - - if (!ino || !attr || !run || !data) - return 1; - - m = data; - - if ((run->lcn + run->length) > m->lcn) { - m->inum = ino->mft_no; - m->lcn = run->lcn + run->length; - } - - return 0; -} - -/** - * main - Begin here - * - * Start from here. - * - * Return: 0 Success, the program worked - * 1 Error, something went wrong - */ -int main(int argc, char *argv[]) -{ - ntfs_volume *vol; - ntfs_inode *ino = NULL; - struct match m; - int result = 1; - - ntfs_log_set_handler(ntfs_log_handler_outerr); - - if (!parse_options(argc, argv)) - return 1; - - utils_set_locale(); - - vol = utils_mount_volume(opts.device, NTFS_MNT_RDONLY | - (opts.force ? NTFS_MNT_FORCE : 0)); - if (!vol) - return 1; - - switch (opts.action) { - case act_sector: - if (opts.range_begin == opts.range_end) - ntfs_log_quiet("Searching for sector %llu\n", - (unsigned long long)opts.range_begin); - else - ntfs_log_quiet("Searching for sector range %llu-%llu\n", (unsigned long long)opts.range_begin, (unsigned long long)opts.range_end); - /* Convert to clusters */ - opts.range_begin >>= (vol->cluster_size_bits - vol->sector_size_bits); - opts.range_end >>= (vol->cluster_size_bits - vol->sector_size_bits); - result = cluster_find(vol, opts.range_begin, opts.range_end, (cluster_cb*)&print_match, NULL); - break; - case act_cluster: - if (opts.range_begin == opts.range_end) - ntfs_log_quiet("Searching for cluster %llu\n", - (unsigned long long)opts.range_begin); - else - ntfs_log_quiet("Searching for cluster range %llu-%llu\n", (unsigned long long)opts.range_begin, (unsigned long long)opts.range_end); - result = cluster_find(vol, opts.range_begin, opts.range_end, (cluster_cb*)&print_match, NULL); - break; - case act_file: - ino = ntfs_pathname_to_inode(vol, NULL, opts.filename); - if (ino) - result = dump_file(vol, ino); - break; - case act_inode: - ino = ntfs_inode_open(vol, opts.inode); - if (ino) { - result = dump_file(vol, ino); - ntfs_inode_close(ino); - } else { - ntfs_log_error("Cannot open inode %llu\n", - (unsigned long long)opts.inode); - } - break; - case act_last: - memset(&m, 0, sizeof(m)); - m.lcn = -1; - result = cluster_find(vol, 0, LONG_MAX, (cluster_cb*)&find_last, &m); - if (m.lcn >= 0) { - ino = ntfs_inode_open(vol, m.inum); - if (ino) { - result = dump_file(vol, ino); - ntfs_inode_close(ino); - } else { - ntfs_log_error("Cannot open inode %llu\n", - (unsigned long long) - opts.inode); - } - result = 0; - } else { - result = 1; - } - break; - case act_info: - default: - result = info(vol); - break; - } - - ntfs_umount(vol, FALSE); - return result; -} - - diff --git a/usr/src/cmd/ntfsprogs/ntfscluster.h b/usr/src/cmd/ntfsprogs/ntfscluster.h deleted file mode 100644 index 5a3d6b3c04..0000000000 --- a/usr/src/cmd/ntfsprogs/ntfscluster.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * ntfscluster - Part of the Linux-NTFS project. - * - * Copyright (c) 2002-2003 Richard Russon - * - * This utility will locate the owner of any given sector or cluster. - * - * 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 Linux-NTFS - * 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 _NTFSCLUSTER_H_ -#define _NTFSCLUSTER_H_ - -#include "types.h" -#include "layout.h" - -enum action { - act_none, - act_info, - act_cluster, - act_sector, - act_inode, - act_file, - act_last, - act_error, -}; - -struct options { - char *device; /* Device/File to work with */ - enum action action; /* What to do */ - int quiet; /* Less output */ - int verbose; /* Extra output */ - int force; /* Override common sense */ - char *filename; /* File to examine */ - u64 inode; /* Inode to examine */ - s64 range_begin; /* Look for objects in this range */ - s64 range_end; -}; - -struct match { - u64 inum; /* Inode number */ - LCN lcn; /* Last cluster in use */ - ATTR_TYPES type; /* Attribute type */ - ntfschar *name; /* Attribute name */ - int name_len; /* Length of attribute name */ -}; - -#endif /* _NTFSCLUSTER_H_ */ - - diff --git a/usr/src/cmd/ntfsprogs/ntfscmp.c b/usr/src/cmd/ntfsprogs/ntfscmp.c deleted file mode 100644 index d247c259b0..0000000000 --- a/usr/src/cmd/ntfsprogs/ntfscmp.c +++ /dev/null @@ -1,1005 +0,0 @@ -/** - * ntfscmp - Part of the Linux-NTFS project. - * - * Copyright (c) 2005-2006 Szabolcs Szakacsits - * Copyright (c) 2005 Anton Altaparmakov - * Copyright (c) 2007 Yura Pakhuchiy - * - * This utility compare two NTFS volumes. - * - * 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 Linux-NTFS - * 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 <unistd.h> -#include <stdlib.h> -#include <stdio.h> -#include <stdarg.h> -#include <string.h> -#include <errno.h> -#include <getopt.h> - -#include "compat.h" -#include "utils.h" -#include "mst.h" -#include "version.h" -#include "support.h" - -static const char *EXEC_NAME = "ntfscmp"; - -static const char *invalid_ntfs_msg = -"Apparently device '%s' doesn't have a valid NTFS.\n" -"Maybe you selected the wrong partition? Or the whole disk instead of a\n" -"partition (e.g. /dev/hda, not /dev/hda1)?\n"; - -static const char *corrupt_volume_msg = -"Apparently you have a corrupted NTFS. Please run the filesystem checker\n" -"on Windows by invoking chkdsk /f. Don't forget the /f (force) parameter,\n" -"it's important! You probably also need to reboot Windows to take effect.\n"; - -static const char *hibernated_volume_msg = -"Apparently the NTFS partition is hibernated. Windows must be resumed and\n" -"turned off properly\n"; - - -static struct { - int debug; - int show_progress; - int verbose; - char *vol1; - char *vol2; -} opt; - - -#define NTFS_PROGBAR 0x0001 -#define NTFS_PROGBAR_SUPPRESS 0x0002 - -struct progress_bar { - u64 start; - u64 stop; - int resolution; - int flags; - float unit; -}; - -/* WARNING: don't modify the text, external tools grep for it */ -#define ERR_PREFIX "ERROR" -#define PERR_PREFIX ERR_PREFIX "(%d): " -#define NERR_PREFIX ERR_PREFIX ": " - -__attribute__((format(printf, 2, 3))) -static void perr_printf(int newline, const char *fmt, ...) -{ - va_list ap; - int eo = errno; - - fprintf(stdout, PERR_PREFIX, eo); - va_start(ap, fmt); - vfprintf(stdout, fmt, ap); - va_end(ap); - fprintf(stdout, ": %s", strerror(eo)); - if (newline) - fprintf(stdout, "\n"); - fflush(stdout); - fflush(stderr); -} - -#define perr_print(...) perr_printf(0, __VA_ARGS__) -#define perr_println(...) perr_printf(1, __VA_ARGS__) - -__attribute__((format(printf, 1, 2))) -static void err_printf(const char *fmt, ...) -{ - va_list ap; - - fprintf(stdout, NERR_PREFIX); - va_start(ap, fmt); - vfprintf(stdout, fmt, ap); - va_end(ap); - fflush(stdout); - fflush(stderr); -} - -/** - * err_exit - * - * Print and error message and exit the program. - */ -__attribute__((noreturn)) -__attribute__((format(printf, 1, 2))) -static int err_exit(const char *fmt, ...) -{ - va_list ap; - - fprintf(stdout, NERR_PREFIX); - va_start(ap, fmt); - vfprintf(stdout, fmt, ap); - va_end(ap); - fflush(stdout); - fflush(stderr); - exit(1); -} - -/** - * perr_exit - * - * Print and error message and exit the program - */ -__attribute__((noreturn)) -__attribute__((format(printf, 1, 2))) -static int perr_exit(const char *fmt, ...) -{ - va_list ap; - int eo = errno; - - fprintf(stdout, PERR_PREFIX, eo); - va_start(ap, fmt); - vfprintf(stdout, fmt, ap); - va_end(ap); - printf(": %s\n", strerror(eo)); - fflush(stdout); - fflush(stderr); - exit(1); -} - -/** - * usage - Print a list of the parameters to the program - * - * Print a list of the parameters and options for the program. - * - * Return: none - */ -__attribute__((noreturn)) -static void usage(void) -{ - - printf("\nUsage: %s [OPTIONS] DEVICE1 DEVICE2\n" - " Compare two NTFS volumes and tell the differences.\n" - "\n" - " -P, --no-progress-bar Don't show progress bar\n" - " -v, --verbose More output\n" - " -h, --help Display this help\n" -#ifdef DEBUG - " -d, --debug Show debug information\n" -#endif - "\n", EXEC_NAME); - printf("%s%s", ntfs_bugs, ntfs_home); - exit(1); -} - - -static void parse_options(int argc, char **argv) -{ - static const char *sopt = "-dhPv"; - static const struct option lopt[] = { -#ifdef DEBUG - { "debug", no_argument, NULL, 'd' }, -#endif - { "help", no_argument, NULL, 'h' }, - { "no-progress-bar", no_argument, NULL, 'P' }, - { "verbose", no_argument, NULL, 'v' }, - { NULL, 0, NULL, 0 } - }; - - int c; - - memset(&opt, 0, sizeof(opt)); - opt.show_progress = 1; - - while ((c = getopt_long(argc, argv, sopt, lopt, NULL)) != -1) { - switch (c) { - case 1: /* A non-option argument */ - if (!opt.vol1) { - opt.vol1 = argv[optind - 1]; - } else if (!opt.vol2) { - opt.vol2 = argv[optind - 1]; - } else { - err_printf("Too many arguments!\n"); - usage(); - } - break; -#ifdef DEBUG - case 'd': - opt.debug++; - break; -#endif - case 'h': - case '?': - usage(); - case 'P': - opt.show_progress = 0; - break; - case 'v': - opt.verbose++; - break; - default: - err_printf("Unknown option '%s'.\n", argv[optind - 1]); - usage(); - break; - } - } - - if (opt.vol1 == NULL || opt.vol2 == NULL) { - err_printf("You must specify exactly 2 volumes.\n"); - usage(); - } - - /* Redirect stderr to stdout, note fflush()es are essential! */ - fflush(stdout); - fflush(stderr); - if (dup2(STDOUT_FILENO, STDERR_FILENO) == -1) { - perror("Failed to redirect stderr to stdout"); - exit(1); - } - fflush(stdout); - fflush(stderr); - -#ifdef DEBUG - if (!opt.debug) - if (!freopen("/dev/null", "w", stderr)) - perr_exit("Failed to redirect stderr to /dev/null"); -#endif -} - -static ntfs_attr_search_ctx *attr_get_search_ctx(ntfs_inode *ni) -{ - ntfs_attr_search_ctx *ret; - - if ((ret = ntfs_attr_get_search_ctx(ni, NULL)) == NULL) - perr_println("ntfs_attr_get_search_ctx"); - - return ret; -} - -static void progress_init(struct progress_bar *p, u64 start, u64 stop, int flags) -{ - p->start = start; - p->stop = stop; - p->unit = 100.0 / (stop - start); - p->resolution = 100; - p->flags = flags; -} - -static void progress_update(struct progress_bar *p, u64 current) -{ - float percent; - - if (!(p->flags & NTFS_PROGBAR)) - return; - if (p->flags & NTFS_PROGBAR_SUPPRESS) - return; - - /* WARNING: don't modify the texts, external tools grep for them */ - percent = p->unit * current; - if (current != p->stop) { - if ((current - p->start) % p->resolution) - return; - printf("%6.2f percent completed\r", percent); - } else - printf("100.00 percent completed\n"); - fflush(stdout); -} - -static u64 inumber(ntfs_inode *ni) -{ - if (ni->nr_extents >= 0) - return ni->mft_no; - - return ni->u.base_ni->mft_no; -} - -static int inode_close(ntfs_inode *ni) -{ - if (ni == NULL) - return 0; - - if (ntfs_inode_close(ni)) { - perr_println("ntfs_inode_close: inode %llu", inumber(ni)); - return -1; - } - return 0; -} - -static inline s64 get_nr_mft_records(ntfs_volume *vol) -{ - return vol->mft_na->initialized_size >> vol->mft_record_size_bits; -} - -#define NTFSCMP_OK 0 -#define NTFSCMP_INODE_OPEN_ERROR 1 -#define NTFSCMP_INODE_OPEN_IO_ERROR 2 -#define NTFSCMP_INODE_OPEN_ENOENT_ERROR 3 -#define NTFSCMP_EXTENSION_RECORD 4 -#define NTFSCMP_INODE_CLOSE_ERROR 5 - -static const char *ntfscmp_errs[] = { - "OK", - "INODE_OPEN_ERROR", - "INODE_OPEN_IO_ERROR", - "INODE_OPEN_ENOENT_ERROR", - "EXTENSION_RECORD", - "INODE_CLOSE_ERROR", - "" -}; - - -static const char *err2string(int err) -{ - return ntfscmp_errs[err]; -} - -static const char *pret2str(void *p) -{ - if (p == NULL) - return "FAILED"; - return "OK"; -} - -static int inode_open(ntfs_volume *vol, MFT_REF mref, ntfs_inode **ni) -{ - *ni = ntfs_inode_open(vol, mref); - if (*ni == NULL) { - if (errno == EIO) - return NTFSCMP_INODE_OPEN_IO_ERROR; - if (errno == ENOENT) - return NTFSCMP_INODE_OPEN_ENOENT_ERROR; - - perr_println("Reading inode %lld failed", mref); - return NTFSCMP_INODE_OPEN_ERROR; - } - - if ((*ni)->mrec->base_mft_record) { - - if (inode_close(*ni) != 0) - return NTFSCMP_INODE_CLOSE_ERROR; - - return NTFSCMP_EXTENSION_RECORD; - } - - return NTFSCMP_OK; -} - -static ntfs_inode *base_inode(ntfs_attr_search_ctx *ctx) -{ - if (ctx->base_ntfs_ino) - return ctx->base_ntfs_ino; - - return ctx->ntfs_ino; -} - -static void print_inode(u64 inum) -{ - printf("Inode %llu ", inum); -} - -static void print_inode_ni(ntfs_inode *ni) -{ - print_inode(inumber(ni)); -} - -static void print_attribute_type(ATTR_TYPES atype) -{ - printf("attribute 0x%x", atype); -} - -static void print_attribute_name(char *name) -{ - if (name) - printf(":%s", name); -} - -#define GET_ATTR_NAME(a) \ - ((ntfschar *)(((u8 *)(a)) + le16_to_cpu((a)->name_offset))), \ - ((a)->name_length) - -static void free_name(char **name) -{ - if (*name) { - free(*name); - *name = NULL; - } -} - -static char *get_attr_name(u64 mft_no, - ATTR_TYPES atype, - const ntfschar *uname, - const int uname_len) -{ - char *name = NULL; - int name_len; - - if (atype == AT_END) - return NULL; - - name_len = ntfs_ucstombs(uname, uname_len, &name, 0); - if (name_len < 0) { - perr_print("ntfs_ucstombs"); - print_inode(mft_no); - print_attribute_type(atype); - puts(""); - exit(1); - - } else if (name_len > 0) - return name; - - free_name(&name); - return NULL; -} - -static char *get_attr_name_na(ntfs_attr *na) -{ - return get_attr_name(inumber(na->ni), na->type, na->name, na->name_len); -} - -static char *get_attr_name_ctx(ntfs_attr_search_ctx *ctx) -{ - u64 mft_no = inumber(ctx->ntfs_ino); - ATTR_TYPES atype = ctx->attr->type; - - return get_attr_name(mft_no, atype, GET_ATTR_NAME(ctx->attr)); -} - -static void print_attribute(ATTR_TYPES atype, char *name) -{ - print_attribute_type(atype); - print_attribute_name(name); - printf(" "); -} - -static void print_na(ntfs_attr *na) -{ - char *name = get_attr_name_na(na); - print_inode_ni(na->ni); - print_attribute(na->type, name); - free_name(&name); -} - -static void print_attribute_ctx(ntfs_attr_search_ctx *ctx) -{ - char *name = get_attr_name_ctx(ctx); - print_attribute(ctx->attr->type, name); - free_name(&name); -} - -static void print_ctx(ntfs_attr_search_ctx *ctx) -{ - char *name = get_attr_name_ctx(ctx); - print_inode_ni(base_inode(ctx)); - print_attribute(ctx->attr->type, name); - free_name(&name); -} - -static void print_differ(ntfs_attr *na) -{ - print_na(na); - printf("content: DIFFER\n"); -} - -static int cmp_buffer(u8 *buf1, u8 *buf2, long long int size, ntfs_attr *na) -{ - if (memcmp(buf1, buf2, size)) { - print_differ(na); - return -1; - } - return 0; -} - -struct cmp_ia { - INDEX_ALLOCATION *ia; - INDEX_ALLOCATION *tmp_ia; - u8 *bitmap; - u8 *byte; - s64 bm_size; -}; - -static int setup_cmp_ia(ntfs_attr *na, struct cmp_ia *cia) -{ - cia->bitmap = ntfs_attr_readall(na->ni, AT_BITMAP, na->name, - na->name_len, &cia->bm_size); - if (!cia->bitmap) { - perr_println("Failed to readall BITMAP"); - return -1; - } - cia->byte = cia->bitmap; - - cia->tmp_ia = cia->ia = ntfs_malloc(na->data_size); - if (!cia->tmp_ia) - goto free_bm; - - if (ntfs_attr_pread(na, 0, na->data_size, cia->ia) != na->data_size) { - perr_println("Failed to pread INDEX_ALLOCATION"); - goto free_ia; - } - - return 0; -free_ia: - free(cia->ia); -free_bm: - free(cia->bitmap); - return -1; -} - -static void cmp_index_allocation(ntfs_attr *na1, ntfs_attr *na2) -{ - struct cmp_ia cia1, cia2; - int bit, ret1, ret2; - u32 ib_size; - - if (setup_cmp_ia(na1, &cia1)) - return; - if (setup_cmp_ia(na2, &cia2)) - return; - /* - * FIXME: ia can be the same even if the bitmap sizes are different. - */ - if (cia1.bm_size != cia1.bm_size) - goto out; - - if (cmp_buffer(cia1.bitmap, cia2.bitmap, cia1.bm_size, na1)) - goto out; - - if (cmp_buffer((u8 *)cia1.ia, (u8 *)cia2.ia, 0x18, na1)) - goto out; - - ib_size = le32_to_cpu(cia1.ia->index.allocated_size) + 0x18; - - bit = 0; - while ((u8 *)cia1.tmp_ia < (u8 *)cia1.ia + na1->data_size) { - if (*cia1.byte & (1 << bit)) { - ret1 = ntfs_mst_post_read_fixup((NTFS_RECORD *) - cia1.tmp_ia, ib_size); - ret2 = ntfs_mst_post_read_fixup((NTFS_RECORD *) - cia2.tmp_ia, ib_size); - if (ret1 != ret2) { - print_differ(na1); - goto out; - } - - if (ret1 == -1) - continue; - - if (cmp_buffer(((u8 *)cia1.tmp_ia) + 0x18, - ((u8 *)cia2.tmp_ia) + 0x18, - le32_to_cpu(cia1.ia-> - index.index_length), na1)) - goto out; - } - - cia1.tmp_ia = (INDEX_ALLOCATION *)((u8 *)cia1.tmp_ia + ib_size); - cia2.tmp_ia = (INDEX_ALLOCATION *)((u8 *)cia2.tmp_ia + ib_size); - - bit++; - if (bit > 7) { - bit = 0; - cia1.byte++; - } - } -out: - free(cia1.ia); - free(cia2.ia); - free(cia1.bitmap); - free(cia2.bitmap); - return; -} - -static void cmp_attribute_data(ntfs_attr *na1, ntfs_attr *na2) -{ - s64 pos; - s64 count1 = 0, count2; - u8 buf1[NTFS_BUF_SIZE]; - u8 buf2[NTFS_BUF_SIZE]; - - for (pos = 0; pos <= na1->data_size; pos += count1) { - - count1 = ntfs_attr_pread(na1, pos, NTFS_BUF_SIZE, buf1); - count2 = ntfs_attr_pread(na2, pos, NTFS_BUF_SIZE, buf2); - - if (count1 != count2) { - print_na(na1); - printf("abrupt length: %lld != %lld ", - na1->data_size, na2->data_size); - printf("(count: %lld != %lld)", count1, count2); - puts(""); - return; - } - - if (count1 == -1) { - err_printf("%s read error: ", "cmp_attribute_data"); - print_na(na1); - printf("len = %lld, pos = %lld\n", na1->data_size, pos); - exit(1); - } - - if (count1 == 0) { - - if (pos + count1 == na1->data_size) - return; /* we are ready */ - - err_printf("%s read error before EOF: ", "cmp_attribute_data"); - print_na(na1); - printf("%lld != %lld\n", pos + count1, na1->data_size); - exit(1); - } - - if (cmp_buffer(buf1, buf2, count1, na1)) - return; - } - - err_printf("%s read overrun: ", "cmp_attribute_data"); - print_na(na1); - err_printf("(len = %lld, pos = %lld, count = %lld)\n", - na1->data_size, pos, count1); - exit(1); -} - -static int cmp_attribute_header(ATTR_RECORD *a1, ATTR_RECORD *a2) -{ - u32 header_size = offsetof(ATTR_RECORD, u.res.resident_end); - - if (a1->non_resident != a2->non_resident) - return 1; - - if (a1->non_resident) { - /* - * FIXME: includes paddings which are not handled by ntfsinfo! - */ - header_size = le32_to_cpu(a1->length); - } - - return memcmp(a1, a2, header_size); -} - -static void cmp_attribute(ntfs_attr_search_ctx *ctx1, - ntfs_attr_search_ctx *ctx2) -{ - ATTR_RECORD *a1 = ctx1->attr; - ATTR_RECORD *a2 = ctx2->attr; - ntfs_attr *na1, *na2; - - if (cmp_attribute_header(a1, a2)) { - print_ctx(ctx1); - printf("header: DIFFER\n"); - } - - na1 = ntfs_attr_open(base_inode(ctx1), a1->type, GET_ATTR_NAME(a1)); - na2 = ntfs_attr_open(base_inode(ctx2), a2->type, GET_ATTR_NAME(a2)); - - if ((!na1 && na2) || (na1 && !na2)) { - print_ctx(ctx1); - printf("open: %s != %s\n", pret2str(na1), pret2str(na2)); - goto close_attribs; - } - - if (na1 == NULL) - goto close_attribs; - - if (na1->data_size != na2->data_size) { - print_na(na1); - printf("length: %lld != %lld\n", na1->data_size, na2->data_size); - goto close_attribs; - } - - if (ntfs_inode_badclus_bad(inumber(ctx1->ntfs_ino), ctx1->attr) == 1) { - /* - * If difference exists then it's already reported at the - * attribute header since the mapping pairs must differ. - */ - return; - } - - if (na1->type == AT_INDEX_ALLOCATION) - cmp_index_allocation(na1, na2); - else - cmp_attribute_data(na1, na2); - -close_attribs: - ntfs_attr_close(na1); - ntfs_attr_close(na2); -} - -static void vprint_attribute(ATTR_TYPES atype, char *name) -{ - if (!opt.verbose) - return; - - printf("0x%x", atype); - if (name) - printf(":%s", name); - printf(" "); -} - -static void print_attributes(ntfs_inode *ni, - ATTR_TYPES atype1, - ATTR_TYPES atype2, - char *name1, - char *name2) -{ - if (!opt.verbose) - return; - - printf("Walking inode %llu attributes: ", inumber(ni)); - vprint_attribute(atype1, name1); - vprint_attribute(atype2, name2); - printf("\n"); -} - -static int new_name(ntfs_attr_search_ctx *ctx, char *prev_name) -{ - int ret = 0; - char *name = get_attr_name_ctx(ctx); - - if (prev_name && name) { - if (strcmp(prev_name, name) != 0) - ret = 1; - } else if (prev_name || name) - ret = 1; - - free_name(&name); - return ret; - -} - -static int new_attribute(ntfs_attr_search_ctx *ctx, - ATTR_TYPES prev_atype, - char *prev_name) -{ - if (!prev_atype && !prev_name) - return 1; - - if (!ctx->attr->non_resident) - return 1; - - if (prev_atype != ctx->attr->type) - return 1; - - if (new_name(ctx, prev_name)) - return 1; - - if (opt.verbose) { - print_inode(base_inode(ctx)->mft_no); - print_attribute_ctx(ctx); - printf("record %llu lowest_vcn %lld: SKIPPED\n", - ctx->ntfs_ino->mft_no, ctx->attr->u.nonres.lowest_vcn); - } - - return 0; -} - -static void set_prev(char **prev_name, ATTR_TYPES *prev_atype, - char *name, ATTR_TYPES atype) -{ - free_name(prev_name); - if (name) { - *prev_name = strdup(name); - if (!*prev_name) - perr_exit("strdup error"); - } - - *prev_atype = atype; -} - -static void set_cmp_attr(ntfs_attr_search_ctx *ctx, ATTR_TYPES *atype, char **name) -{ - *atype = ctx->attr->type; - - free_name(name); - *name = get_attr_name_ctx(ctx); -} - -static int next_attr(ntfs_attr_search_ctx *ctx, ATTR_TYPES *atype, char **name, - int *err) -{ - int ret; - - ret = ntfs_attrs_walk(ctx); - *err = errno; - if (ret) { - *atype = AT_END; - free_name(name); - } else - set_cmp_attr(ctx, atype, name); - - return ret; -} - -static int cmp_attributes(ntfs_inode *ni1, ntfs_inode *ni2) -{ - int ret = -1; - int old_ret1, ret1 = 0, ret2 = 0; - int errno1 = 0, errno2 = 0; - char *prev_name = NULL, *name1 = NULL, *name2 = NULL; - ATTR_TYPES old_atype1, prev_atype = 0, atype1, atype2; - ntfs_attr_search_ctx *ctx1, *ctx2; - - if (!(ctx1 = attr_get_search_ctx(ni1))) - return -1; - if (!(ctx2 = attr_get_search_ctx(ni2))) - goto out; - - set_cmp_attr(ctx1, &atype1, &name1); - set_cmp_attr(ctx2, &atype2, &name2); - - while (1) { - - old_atype1 = atype1; - old_ret1 = ret1; - if (!ret1 && (le32_to_cpu(atype1) <= le32_to_cpu(atype2) || - ret2)) - ret1 = next_attr(ctx1, &atype1, &name1, &errno1); - if (!ret2 && (le32_to_cpu(old_atype1) >= le32_to_cpu(atype2) || - old_ret1)) - ret2 = next_attr(ctx2, &atype2, &name2, &errno2); - - print_attributes(ni1, atype1, atype2, name1, name2); - - if (ret1 && ret2) { - if (errno1 != errno2) { - print_inode_ni(ni1); - printf("attribute walk (errno): %d != %d\n", - errno1, errno2); - } - break; - } - - if (ret2 || le32_to_cpu(atype1) < le32_to_cpu(atype2)) { - if (new_attribute(ctx1, prev_atype, prev_name)) { - print_ctx(ctx1); - printf("presence: EXISTS != MISSING\n"); - set_prev(&prev_name, &prev_atype, name1, - atype1); - } - - } else if (ret1 || le32_to_cpu(atype1) > le32_to_cpu(atype2)) { - if (new_attribute(ctx2, prev_atype, prev_name)) { - print_ctx(ctx2); - printf("presence: MISSING != EXISTS \n"); - set_prev(&prev_name, &prev_atype, name2, atype2); - } - - } else /* atype1 == atype2 */ { - if (new_attribute(ctx1, prev_atype, prev_name)) { - cmp_attribute(ctx1, ctx2); - set_prev(&prev_name, &prev_atype, name1, atype1); - } - } - } - - free_name(&prev_name); - ret = 0; - ntfs_attr_put_search_ctx(ctx2); -out: - ntfs_attr_put_search_ctx(ctx1); - return ret; -} - -static int cmp_inodes(ntfs_volume *vol1, ntfs_volume *vol2) -{ - u64 inode; - int ret1, ret2; - ntfs_inode *ni1, *ni2; - struct progress_bar progress; - int pb_flags = 0; /* progress bar flags */ - u64 nr_mft_records, nr_mft_records2; - - if (opt.show_progress) - pb_flags |= NTFS_PROGBAR; - - nr_mft_records = get_nr_mft_records(vol1); - nr_mft_records2 = get_nr_mft_records(vol2); - - if (nr_mft_records != nr_mft_records2) { - - printf("Number of mft records: %lld != %lld\n", - nr_mft_records, nr_mft_records2); - - if (nr_mft_records > nr_mft_records2) - nr_mft_records = nr_mft_records2; - } - - progress_init(&progress, 0, nr_mft_records - 1, pb_flags); - progress_update(&progress, 0); - - for (inode = 0; inode < nr_mft_records; inode++) { - - ret1 = inode_open(vol1, (MFT_REF)inode, &ni1); - ret2 = inode_open(vol2, (MFT_REF)inode, &ni2); - - if (ret1 != ret2) { - print_inode(inode); - printf("open: %s != %s\n", - err2string(ret1), err2string(ret2)); - goto close_inodes; - } - - if (ret1 != NTFSCMP_OK) - goto close_inodes; - - if (cmp_attributes(ni1, ni2) != 0) { - inode_close(ni1); - inode_close(ni2); - return -1; - } -close_inodes: - if (inode_close(ni1) != 0) - return -1; - if (inode_close(ni2) != 0) - return -1; - - progress_update(&progress, inode); - } - return 0; -} - -static ntfs_volume *mount_volume(const char *volume) -{ - unsigned long mntflag; - ntfs_volume *vol = NULL; - - if (ntfs_check_if_mounted(volume, &mntflag)) { - perr_println("Failed to check '%s' mount state", volume); - printf("Probably /etc/mtab is missing. It's too risky to " - "continue. You might try\nan another Linux distro.\n"); - exit(1); - } - if (mntflag & NTFS_MF_MOUNTED) { - if (!(mntflag & NTFS_MF_READONLY)) - err_exit("Device '%s' is mounted read-write. " - "You must 'umount' it first.\n", volume); - } - - vol = ntfs_mount(volume, NTFS_MNT_RDONLY); - if (vol == NULL) { - - int err = errno; - - perr_println("Opening '%s' as NTFS failed", volume); - if (err == EINVAL) - printf(invalid_ntfs_msg, volume); - else if (err == EIO) - puts(corrupt_volume_msg); - else if (err == EPERM) - puts(hibernated_volume_msg); - exit(1); - } - - return vol; -} - -int main(int argc, char **argv) -{ - ntfs_volume *vol1; - ntfs_volume *vol2; - - printf("%s v%s (libntfs %s)\n", EXEC_NAME, VERSION, - ntfs_libntfs_version()); - - parse_options(argc, argv); - - utils_set_locale(); - - vol1 = mount_volume(opt.vol1); - vol2 = mount_volume(opt.vol2); - - if (cmp_inodes(vol1, vol2) != 0) - exit(1); - - ntfs_umount(vol1, FALSE); - ntfs_umount(vol2, FALSE); - - exit(0); -} - diff --git a/usr/src/cmd/ntfsprogs/ntfscp.c b/usr/src/cmd/ntfsprogs/ntfscp.c deleted file mode 100644 index 0019667a1e..0000000000 --- a/usr/src/cmd/ntfsprogs/ntfscp.c +++ /dev/null @@ -1,584 +0,0 @@ -/** - * ntfscp - Part of the Linux-NTFS project. - * - * Copyright (c) 2004-2007 Yura Pakhuchiy - * Copyright (c) 2005 Anton Altaparmakov - * Copyright (c) 2006 Hil Liao - * - * This utility will copy file to an NTFS volume. - * - * 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 Linux-NTFS - * 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_STDIO_H -#include <stdio.h> -#endif -#ifdef HAVE_GETOPT_H -#include <getopt.h> -#endif -#ifdef HAVE_STDLIB_H -#include <stdlib.h> -#endif -#ifdef HAVE_STRING_H -#include <string.h> -#endif -#include <signal.h> -#ifdef HAVE_SYS_STAT_H -#include <sys/stat.h> -#endif -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif -#ifdef HAVE_LIBGEN_H -#include <libgen.h> -#endif - -#include "compat.h" -#include "types.h" -#include "attrib.h" -#include "utils.h" -#include "volume.h" -#include "dir.h" -#include "debug.h" -#include "version.h" -#include "logging.h" - -struct options { - char *device; /* Device/File to work with */ - char *src_file; /* Source file */ - char *dest_file; /* Destination file */ - char *attr_name; /* Write to attribute with this name. */ - int force; /* Override common sense */ - int quiet; /* Less output */ - int verbose; /* Extra output */ - int noaction; /* Do not write to disk */ - ATTR_TYPES attribute; /* Write to this attribute. */ - int inode; /* Treat dest_file as inode number. */ -}; - -static const char *EXEC_NAME = "ntfscp"; -static struct options opts; -static volatile sig_atomic_t caught_terminate = 0; - -/** - * version - Print version information about the program - * - * Print a copyright statement and a brief description of the program. - * - * Return: none - */ -static void version(void) -{ - ntfs_log_info("\n%s v%s (libntfs %s) - Copy file to an NTFS " - "volume.\n\n", EXEC_NAME, VERSION, ntfs_libntfs_version()); - ntfs_log_info("Copyright (c) 2004-2007 Yura Pakhuchiy\n"); - ntfs_log_info("Copyright (c) 2005 Anton Altaparmakov\n"); - ntfs_log_info("Copyright (c) 2006 Hil Liao\n"); - ntfs_log_info("\n%s\n%s%s\n", ntfs_gpl, ntfs_bugs, ntfs_home); -} - -/** - * usage - Print a list of the parameters to the program - * - * Print a list of the parameters and options for the program. - * - * Return: none - */ -static void usage(void) -{ - ntfs_log_info("\nUsage: %s [options] device src_file dest_file\n\n" - " -a, --attribute NUM Write to this attribute\n" - " -i, --inode Treat dest_file as inode number\n" - " -f, --force Use less caution\n" - " -h, --help Print this help\n" - " -N, --attr-name NAME Write to attribute with this name\n" - " -n, --no-action Do not write to disk\n" - " -q, --quiet Less output\n" - " -V, --version Version information\n" - " -v, --verbose More output\n\n", - EXEC_NAME); - ntfs_log_info("%s%s\n", ntfs_bugs, ntfs_home); -} - -/** - * parse_options - Read and validate the programs command line - * - * Read the command line, verify the syntax and parse the options. - * This function is very long, but quite simple. - * - * Return: 1 Success - * 0 Error, one or more problems - */ -static int parse_options(int argc, char **argv) -{ - static const char *sopt = "-a:ifh?N:nqVv"; - static const struct option lopt[] = { - { "attribute", required_argument, NULL, 'a' }, - { "inode", no_argument, NULL, 'i' }, - { "force", no_argument, NULL, 'f' }, - { "help", no_argument, NULL, 'h' }, - { "attr-name", required_argument, NULL, 'N' }, - { "no-action", no_argument, NULL, 'n' }, - { "quiet", no_argument, NULL, 'q' }, - { "version", no_argument, NULL, 'V' }, - { "verbose", no_argument, NULL, 'v' }, - { NULL, 0, NULL, 0 } - }; - - char *s; - int c = -1; - int err = 0; - int ver = 0; - int help = 0; - int levels = 0; - s64 attr; - - opts.device = NULL; - opts.src_file = NULL; - opts.dest_file = NULL; - opts.attr_name = NULL; - opts.inode = 0; - opts.attribute = AT_DATA; - - 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 = argv[optind - 1]; - } else if (!opts.src_file) { - opts.src_file = argv[optind - 1]; - } else if (!opts.dest_file) { - opts.dest_file = argv[optind - 1]; - } else { - ntfs_log_error("You must specify exactly two " - "files.\n"); - err++; - } - break; - case 'a': - if (opts.attribute != AT_DATA) { - ntfs_log_error("You can specify only one " - "attribute.\n"); - err++; - break; - } - - attr = strtol(optarg, &s, 0); - if (*s) { - ntfs_log_error("Couldn't parse attribute.\n"); - err++; - } else - opts.attribute = (ATTR_TYPES)cpu_to_le32(attr); - break; - case 'i': - opts.inode++; - break; - case 'f': - opts.force++; - break; - case 'h': - case '?': - if (strncmp(argv[optind - 1], "--log-", 6) == 0) { - if (!ntfs_log_parse_option(argv[optind - 1])) - err++; - break; - } - help++; - break; - case 'N': - if (opts.attr_name) { - ntfs_log_error("You can specify only one " - "attribute name.\n"); - err++; - } else - opts.attr_name = argv[optind - 1]; - break; - case 'n': - opts.noaction++; - break; - case 'q': - opts.quiet++; - ntfs_log_clear_levels(NTFS_LOG_LEVEL_QUIET); - break; - case 'V': - ver++; - break; - case 'v': - opts.verbose++; - ntfs_log_set_levels(NTFS_LOG_LEVEL_VERBOSE); - break; - default: - ntfs_log_error("Unknown option '%s'.\n", - argv[optind - 1]); - err++; - break; - } - } - - /* Make sure we're in sync with the log levels */ - levels = ntfs_log_get_levels(); - if (levels & NTFS_LOG_LEVEL_VERBOSE) - opts.verbose++; - if (!(levels & NTFS_LOG_LEVEL_QUIET)) - opts.quiet++; - - if (help || ver) { - opts.quiet = 0; - } else { - if (!opts.device) { - ntfs_log_error("You must specify a device.\n"); - err++; - } else if (!opts.src_file) { - ntfs_log_error("You must specify a source file.\n"); - err++; - } else if (!opts.dest_file) { - ntfs_log_error("You must specify a destination " - "file.\n"); - err++; - } - - if (opts.quiet && opts.verbose) { - ntfs_log_error("You may not use --quiet and --verbose " - "at the same time.\n"); - err++; - } - } - - if (ver) - version(); - if (help || err) - usage(); - - return (!err && !help && !ver); -} - -/** - * signal_handler - Handle SIGINT and SIGTERM: abort write, sync and exit. - */ -static void signal_handler(int arg __attribute__((unused))) -{ - caught_terminate++; -} - -/** - * Create a regular file under the given directory inode - * - * It is a wrapper function to ntfs_create(...) - * - * Return: the created file inode - */ -static ntfs_inode *ntfs_new_file(ntfs_inode *dir_ni, - const char *filename) -{ - ntfschar *ufilename; - /* inode to the file that is being created */ - ntfs_inode *ni; - int ufilename_len; - - /* ntfs_mbstoucs(...) will allocate memory for ufilename if it's NULL */ - ufilename = NULL; - ufilename_len = ntfs_mbstoucs(filename, &ufilename, 0); - if (ufilename_len == -1) { - ntfs_log_perror("ERROR: Failed to convert '%s' to unicode", - filename); - return NULL; - } - ni = ntfs_create(dir_ni, ufilename, ufilename_len, S_IFREG); - free(ufilename); - return ni; -} - -/** - * main - Begin here - * - * Start from here. - * - * Return: 0 Success, the program worked - * 1 Error, something went wrong - */ -int main(int argc, char *argv[]) -{ - FILE *in; - ntfs_volume *vol; - ntfs_inode *out; - ntfs_attr *na; - int flags = 0; - int result = 1; - s64 new_size; - u64 offset; - char *buf; - s64 br, bw; - ntfschar *attr_name; - int attr_name_len = 0; - - ntfs_log_set_handler(ntfs_log_handler_stderr); - - if (!parse_options(argc, argv)) - return 1; - - utils_set_locale(); - - /* Set SIGINT handler. */ - if (signal(SIGINT, signal_handler) == SIG_ERR) { - ntfs_log_perror("Failed to set SIGINT handler"); - return 1; - } - /* Set SIGTERM handler. */ - if (signal(SIGTERM, signal_handler) == SIG_ERR) { - ntfs_log_perror("Failed to set SIGTERM handler"); - return 1; - } - - if (opts.noaction) - flags = NTFS_MNT_RDONLY; - if (opts.force) - flags |= NTFS_MNT_FORCE; - - vol = utils_mount_volume(opts.device, flags); - if (!vol) { - ntfs_log_perror("ERROR: couldn't mount volume"); - return 1; - } - - if (NVolWasDirty(vol) && !opts.force) - goto umount; - - { - struct stat fst; - if (stat(opts.src_file, &fst) == -1) { - ntfs_log_perror("ERROR: Couldn't stat source file"); - goto umount; - } - new_size = fst.st_size; - } - ntfs_log_verbose("New file size: %lld\n", new_size); - - in = fopen(opts.src_file, "r"); - if (!in) { - ntfs_log_perror("ERROR: Couldn't open source file"); - goto umount; - } - - if (opts.inode) { - s64 inode_num; - char *s; - - inode_num = strtoll(opts.dest_file, &s, 0); - if (*s) { - ntfs_log_error("ERROR: Couldn't parse inode number.\n"); - goto close_src; - } - out = ntfs_inode_open(vol, inode_num); - } else - out = ntfs_pathname_to_inode(vol, NULL, opts.dest_file); - if (!out) { - /* Copy the file if the dest_file's parent dir can be opened. */ - char *parent_dirname; - char *filename; - ntfs_inode *dir_ni; - ntfs_inode *ni; - int dest_path_len; - char *dirname_last_whack; - - filename = basename(opts.dest_file); - dest_path_len = strlen(opts.dest_file); - parent_dirname = strdup(opts.dest_file); - if (!parent_dirname) { - ntfs_log_perror("strdup() failed"); - goto close_src; - } - dirname_last_whack = strrchr(parent_dirname, '/'); - if (dirname_last_whack) { - dirname_last_whack[1] = 0; - dir_ni = ntfs_pathname_to_inode(vol, NULL, - parent_dirname); - } else { - ntfs_log_verbose("Target path does not contain '/'. " - "Using root directory as parent.\n"); - dir_ni = ntfs_inode_open(vol, FILE_root); - } - if (dir_ni) { - if (!(dir_ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)) { - /* Remove the last '/' for estetic reasons. */ - dirname_last_whack[0] = 0; - ntfs_log_error("The file '%s' already exists " - "and is not a directory. " - "Aborting.\n", parent_dirname); - free(parent_dirname); - ntfs_inode_close(dir_ni); - goto close_src; - } - ntfs_log_verbose("Creating a new file '%s' under '%s'" - "\n", filename, parent_dirname); - ni = ntfs_new_file(dir_ni, filename); - ntfs_inode_close(dir_ni); - if (!ni) { - ntfs_log_perror("Failed to create '%s' under " - "'%s'", filename, - parent_dirname); - free(parent_dirname); - goto close_src; - } - out = ni; - } else { - ntfs_log_perror("ERROR: Couldn't open '%s'", - parent_dirname); - free(parent_dirname); - goto close_src; - } - free(parent_dirname); - } - /* The destination is a directory. */ - if ((out->mrec->flags & MFT_RECORD_IS_DIRECTORY) && !opts.inode) { - char *filename; - char *overwrite_filename; - int overwrite_filename_len; - ntfs_inode *ni; - ntfs_inode *dir_ni; - int filename_len; - int dest_dirname_len; - - filename = basename(opts.src_file); - dir_ni = out; - filename_len = strlen(filename); - dest_dirname_len = strlen(opts.dest_file); - overwrite_filename_len = filename_len+dest_dirname_len + 2; - overwrite_filename = malloc(overwrite_filename_len); - if (!overwrite_filename) { - ntfs_log_perror("ERROR: Failed to allocate %i bytes " - "memory for the overwrite filename", - overwrite_filename_len); - ntfs_inode_close(out); - goto close_src; - } - strcpy(overwrite_filename, opts.dest_file); - if (opts.dest_file[dest_dirname_len - 1] != '/') { - strcat(overwrite_filename, "/"); - } - strcat(overwrite_filename, filename); - ni = ntfs_pathname_to_inode(vol, NULL, overwrite_filename); - /* Does a file with the same name exist in the dest dir? */ - if (ni) { - ntfs_log_verbose("Destination path has a file with " - "the same name\nOverwriting the file " - "'%s'\n", overwrite_filename); - ntfs_inode_close(out); - out = ni; - } else { - ntfs_log_verbose("Creating a new file '%s' under " - "'%s'\n", filename, opts.dest_file); - ni = ntfs_new_file(dir_ni, filename); - ntfs_inode_close(dir_ni); - if (!ni) { - ntfs_log_perror("ERROR: Failed to create the " - "destination file under '%s'", - opts.dest_file); - free(overwrite_filename); - goto close_src; - } - out = ni; - } - free(overwrite_filename); - } - - attr_name = ntfs_str2ucs(opts.attr_name, &attr_name_len); - if (!attr_name) { - ntfs_log_perror("ERROR: Failed to parse attribute name '%s'", - opts.attr_name); - goto close_dst; - } - - na = ntfs_attr_open(out, opts.attribute, attr_name, attr_name_len); - if (!na) { - if (errno != ENOENT) { - ntfs_log_perror("ERROR: Couldn't open attribute"); - goto close_dst; - } - /* Requested attribute isn't present, add it. */ - if (ntfs_attr_add(out, opts.attribute, attr_name, - attr_name_len, NULL, 0)) { - ntfs_log_perror("ERROR: Couldn't add attribute"); - goto close_dst; - } - na = ntfs_attr_open(out, opts.attribute, attr_name, - attr_name_len); - if (!na) { - ntfs_log_perror("ERROR: Couldn't open just added " - "attribute"); - goto close_dst; - } - } - ntfs_ucsfree(attr_name); - - ntfs_log_verbose("Old file size: %lld\n", na->data_size); - if (na->data_size != new_size) { - if (__ntfs_attr_truncate(na, new_size, FALSE)) { - ntfs_log_perror("ERROR: Couldn't resize attribute"); - goto close_attr; - } - } - - buf = malloc(NTFS_BUF_SIZE); - if (!buf) { - ntfs_log_perror("ERROR: malloc failed"); - goto close_attr; - } - - ntfs_log_verbose("Starting write.\n"); - offset = 0; - while (!feof(in)) { - if (caught_terminate) { - ntfs_log_error("SIGTERM or SIGINT received. " - "Aborting write.\n"); - break; - } - br = fread(buf, 1, NTFS_BUF_SIZE, in); - if (!br) { - if (!feof(in)) ntfs_log_perror("ERROR: fread failed"); - break; - } - bw = ntfs_attr_pwrite(na, offset, br, buf); - if (bw != br) { - ntfs_log_perror("ERROR: ntfs_attr_pwrite failed"); - break; - } - offset += bw; - } - ntfs_log_verbose("Syncing.\n"); - result = 0; - free(buf); -close_attr: - ntfs_attr_close(na); -close_dst: - while (ntfs_inode_close(out)) { - if (errno != EBUSY) { - ntfs_log_error("Sync failed. Run chkdsk.\n"); - break; - } - ntfs_log_error("Device busy. Will retry sync in 3 seconds.\n"); - sleep(3); - } -close_src: - fclose(in); -umount: - ntfs_umount(vol, FALSE); - ntfs_log_verbose("Done.\n"); - return result; -} diff --git a/usr/src/cmd/ntfsprogs/ntfsfix.c b/usr/src/cmd/ntfsprogs/ntfsfix.c deleted file mode 100644 index dd1d1f7585..0000000000 --- a/usr/src/cmd/ntfsprogs/ntfsfix.c +++ /dev/null @@ -1,542 +0,0 @@ -/** - * ntfsfix - Part of the Linux-NTFS project. - * - * Copyright (c) 2000-2006 Anton Altaparmakov - * Copyright (c) 2002-2006 Szabolcs Szakacsits - * Copyright (c) 2007 Yura Pakhuchiy - * - * This utility fixes some common NTFS problems, resets the NTFS journal file - * and schedules an NTFS consistency check for the first boot into Windows. - * - * Anton Altaparmakov <aia21@cantab.net> - * - * 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 Linux-NTFS source - * in the file COPYING); if not, write to the Free Software Foundation, - * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* - * WARNING: This program might not work on architectures which do not allow - * unaligned access. For those, the program would need to start using - * get/put_unaligned macros (#include <asm/unaligned.h>), but not doing it yet, - * since NTFS really mostly applies to ia32 only, which does allow unaligned - * accesses. We might not actually have a problem though, since the structs are - * defined as being packed so that might be enough for gcc to insert the - * correct code. - * - * If anyone using a non-little endian and/or an aligned access only CPU tries - * this program please let me know whether it works or not! - * - * Anton Altaparmakov <aia21@cantab.net> - */ - -#include "config.h" - -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif -#ifdef HAVE_STDLIB_H -#include <stdlib.h> -#endif -#ifdef HAVE_STDIO_H -#include <stdio.h> -#endif -#ifdef HAVE_FCNTL_H -#include <fcntl.h> -#endif -#ifdef HAVE_ERRNO_H -#include <errno.h> -#endif -#ifdef HAVE_STRING_H -#include <string.h> -#endif -#ifdef HAVE_GETOPT_H -#include <getopt.h> -#endif - -#include "compat.h" -#include "types.h" -#include "attrib.h" -#include "mft.h" -#include "device.h" -#include "logfile.h" -#include "utils.h" -#include "version.h" -#include "logging.h" - -#ifdef NO_NTFS_DEVICE_DEFAULT_IO_OPS -# error "No default device io operations! Cannot build ntfsfix. \ -You need to run ./configure without the --disable-default-device-io-ops \ -switch if you want to be able to build the NTFS utilities." -#endif - -static const char *EXEC_NAME = "ntfsfix"; -static const char *OK = "OK\n"; -static const char *FAILED = "FAILED\n"; - -static struct { - char *volume; -} opt; - -/** - * usage - */ -__attribute__((noreturn)) -static int usage(void) -{ - ntfs_log_info("%s v%s (libntfs %s)\n" - "\n" - "Usage: %s [options] device\n" - " Attempt to fix an NTFS partition.\n" - "\n" - " -h, --help Display this help\n" - " -V, --version Display version information\n" - "\n" - "For example: %s /dev/hda6\n\n", - EXEC_NAME, VERSION, ntfs_libntfs_version(), EXEC_NAME, - EXEC_NAME); - ntfs_log_info("%s%s", ntfs_bugs, ntfs_home); - exit(1); -} - -/** - * version - */ -__attribute__((noreturn)) -static void version(void) -{ - ntfs_log_info("%s v%s\n\n" - "Attempt to fix an NTFS partition.\n\n" - "Copyright (c) 2000-2006 Anton Altaparmakov\n" - "Copyright (c) 2002-2006 Szabolcs Szakacsits\n" - "Copyright (c) 2007 Yura Pakhuchiy\n\n", - EXEC_NAME, VERSION); - ntfs_log_info("%s\n%s%s", ntfs_gpl, ntfs_bugs, ntfs_home); - exit(1); -} - -/** - * parse_options - */ -static void parse_options(int argc, char **argv) -{ - int c; - static const char *sopt = "-hV"; - static const struct option lopt[] = { - { "help", no_argument, NULL, 'h' }, - { "version", no_argument, NULL, 'V' }, - { NULL, 0, NULL, 0 } - }; - - memset(&opt, 0, sizeof(opt)); - - while ((c = getopt_long(argc, argv, sopt, lopt, NULL)) != -1) { - switch (c) { - case 1: /* A non-option argument */ - if (!opt.volume) - opt.volume = argv[optind - 1]; - else { - ntfs_log_info("ERROR: Too many arguments.\n"); - usage(); - } - break; - case 'h': - case '?': - usage(); - case 'V': - version(); - default: - ntfs_log_info("ERROR: Unknown option '%s'.\n", argv[optind - 1]); - usage(); - } - } - - if (opt.volume == NULL) { - ntfs_log_info("ERROR: You must specify a device.\n"); - usage(); - } -} - -/** - * OLD_ntfs_volume_set_flags - */ -static int OLD_ntfs_volume_set_flags(ntfs_volume *vol, const le16 flags) -{ - MFT_RECORD *m = NULL; - ATTR_RECORD *a; - VOLUME_INFORMATION *c; - ntfs_attr_search_ctx *ctx; - int ret = -1; /* failure */ - - if (!vol) { - errno = EINVAL; - return -1; - } - if (ntfs_file_record_read(vol, FILE_Volume, &m, NULL)) { - ntfs_log_perror("Failed to read $Volume"); - return -1; - } - /* Sanity check */ - if (!(m->flags & MFT_RECORD_IN_USE)) { - ntfs_log_error("$Volume has been deleted. Cannot handle this " - "yet. Run chkdsk to fix this.\n"); - errno = EIO; - goto err_exit; - } - /* Get a pointer to the volume information attribute. */ - ctx = ntfs_attr_get_search_ctx(NULL, m); - if (!ctx) { - ntfs_log_debug("Failed to allocate attribute search " - "context.\n"); - goto err_exit; - } - 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 " - "(and 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->u.res.value_offset) + (char*)a); - /* Sanity checks. */ - if ((char*)c + le32_to_cpu(a->u.res.value_length) > - (char*)m + le32_to_cpu(m->bytes_in_use) || - le16_to_cpu(a->u.res.value_offset) + - le32_to_cpu(a->u.res.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; - if (ntfs_mft_record_write(vol, FILE_Volume, m)) { - ntfs_log_perror("Error writing $Volume"); - goto err_out; - } - ret = 0; /* success */ -err_out: - ntfs_attr_put_search_ctx(ctx); -err_exit: - free(m); - return ret; -} - -/** - * set_dirty_flag - */ -static int set_dirty_flag(ntfs_volume *vol) -{ - le16 flags; - - if (NVolWasDirty(vol)) - return 0; - ntfs_log_info("Setting required flags on partition... "); - /* - * Set chkdsk flag, i.e. mark the partition dirty so chkdsk will run - * and fix it for us. - */ - flags = vol->flags | VOLUME_IS_DIRTY; - if (OLD_ntfs_volume_set_flags(vol, flags)) { - ntfs_log_info(FAILED); - ntfs_log_error("Error setting volume flags.\n"); - return -1; - } - vol->flags = flags; - NVolSetWasDirty(vol); - ntfs_log_info(OK); - return 0; -} - -/** - * empty_journal - */ -static int empty_journal(ntfs_volume *vol) -{ - if (NVolLogFileEmpty(vol)) - return 0; - ntfs_log_info("Going to empty the journal ($LogFile)... "); - if (ntfs_logfile_reset(vol)) { - ntfs_log_info(FAILED); - ntfs_log_perror("Failed to reset $LogFile"); - return -1; - } - ntfs_log_info(OK); - return 0; -} - -/** - * fix_mftmirr - */ -static int fix_mftmirr(ntfs_volume *vol) -{ - s64 l, br; - unsigned char *m, *m2; - int i, ret = -1; /* failure */ - BOOL done; - - ntfs_log_info("\nProcessing $MFT and $MFTMirr...\n"); - - /* Load data from $MFT and $MFTMirr and compare the contents. */ - m = (u8*)malloc(vol->mftmirr_size << vol->mft_record_size_bits); - if (!m) { - ntfs_log_perror("Failed to allocate memory"); - return -1; - } - m2 = (u8*)malloc(vol->mftmirr_size << vol->mft_record_size_bits); - if (!m2) { - ntfs_log_perror("Failed to allocate memory"); - free(m); - return -1; - } - - ntfs_log_info("Reading $MFT... "); - l = ntfs_attr_mst_pread(vol->mft_na, 0, vol->mftmirr_size, - vol->mft_record_size, m); - if (l != vol->mftmirr_size) { - ntfs_log_info(FAILED); - if (l != -1) - errno = EIO; - ntfs_log_perror("Failed to read $MFT"); - goto error_exit; - } - ntfs_log_info(OK); - - ntfs_log_info("Reading $MFTMirr... "); - l = ntfs_attr_mst_pread(vol->mftmirr_na, 0, vol->mftmirr_size, - vol->mft_record_size, m2); - if (l != vol->mftmirr_size) { - ntfs_log_info(FAILED); - if (l != -1) - errno = EIO; - ntfs_log_perror("Failed to read $MFTMirr"); - goto error_exit; - } - ntfs_log_info(OK); - - /* - * FIXME: Need to actually check the $MFTMirr for being real. Otherwise - * we might corrupt the partition if someone is experimenting with - * software RAID and the $MFTMirr is not actually in the position we - * expect it to be... )-: - * FIXME: We should emit a warning it $MFTMirr is damaged and ask - * user whether to recreate it from $MFT or whether to abort. - The - * warning needs to include the danger of software RAID arrays. - * Maybe we should go as far as to detect whether we are running on a - * MD disk and if yes then bomb out right at the start of the program? - */ - - ntfs_log_info("Comparing $MFTMirr to $MFT... "); - done = FALSE; - 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; - BOOL use_mirr; - - if (i < 12) - s = ESTR[i]; - else if (i < 16) - s = "system file"; - else - s = "mft record"; - - use_mirr = FALSE; - mrec = (MFT_RECORD*)(m + i * vol->mft_record_size); - if (mrec->flags & MFT_RECORD_IN_USE) { - if (ntfs_is_baad_record(mrec->magic)) { - ntfs_log_info(FAILED); - ntfs_log_error("$MFT error: Incomplete multi " - "sector transfer detected in " - "%s.\nCannot handle this yet. " - ")-:\n", s); - goto error_exit; - } - if (!ntfs_is_mft_record(mrec->magic)) { - ntfs_log_info(FAILED); - ntfs_log_error("$MFT error: Invalid mft " - "record for %s.\nCannot " - "handle this yet. )-:\n", s); - goto error_exit; - } - } - mrec2 = (MFT_RECORD*)(m2 + i * vol->mft_record_size); - if (mrec2->flags & MFT_RECORD_IN_USE) { - if (ntfs_is_baad_record(mrec2->magic)) { - ntfs_log_info(FAILED); - ntfs_log_error("$MFTMirr error: Incomplete " - "multi sector transfer " - "detected in %s.\n", s); - goto error_exit; - } - if (!ntfs_is_mft_record(mrec2->magic)) { - ntfs_log_info(FAILED); - ntfs_log_error("$MFTMirr error: Invalid mft " - "record for %s.\n", s); - goto error_exit; - } - /* $MFT is corrupt but $MFTMirr is ok, use $MFTMirr. */ - if (!(mrec->flags & MFT_RECORD_IN_USE) && - !ntfs_is_mft_record(mrec->magic)) - use_mirr = TRUE; - } - if (memcmp(mrec, mrec2, ntfs_mft_record_get_data_size(mrec))) { - if (!done) { - done = TRUE; - ntfs_log_info(FAILED); - } - ntfs_log_info("Correcting differences in $MFT%s " - "record %d...", use_mirr ? "" : "Mirr", - i); - br = ntfs_mft_record_write(vol, i, - use_mirr ? mrec2 : mrec); - if (br) { - ntfs_log_info(FAILED); - ntfs_log_perror("Error correcting $MFT%s", - use_mirr ? "" : "Mirr"); - goto error_exit; - } - ntfs_log_info(OK); - } - } - if (!done) - ntfs_log_info(OK); - ntfs_log_info("Processing of $MFT and $MFTMirr completed " - "successfully.\n"); - ret = 0; -error_exit: - free(m); - free(m2); - return ret; -} - -/** - * fix_mount - */ -static int fix_mount(void) -{ - int ret = -1; /* failure */ - ntfs_volume *vol; - struct ntfs_device *dev; - - ntfs_log_info("Attempting to correct errors... "); - - dev = ntfs_device_alloc(opt.volume, 0, &ntfs_device_default_io_ops, - NULL); - if (!dev) { - ntfs_log_info(FAILED); - ntfs_log_perror("Failed to allocate device"); - return -1; - } - vol = ntfs_volume_startup(dev, 0); - if (!vol) { - ntfs_log_info(FAILED); - ntfs_log_perror("Failed to startup volume"); - ntfs_log_error("Volume is corrupt. You should run chkdsk.\n"); - ntfs_device_free(dev); - return -1; - } - if (fix_mftmirr(vol) < 0) - goto error_exit; - if (set_dirty_flag(vol) < 0) - goto error_exit; - if (empty_journal(vol) < 0) - goto error_exit; - ret = 0; -error_exit: - /* ntfs_umount() will invoke ntfs_device_free() for us. */ - if (ntfs_umount(vol, 0)) - ntfs_umount(vol, 1); - return ret; -} - -/** - * main - */ -int main(int argc, char **argv) -{ - ntfs_volume *vol; - unsigned long mnt_flags; - int ret = 1; /* failure */ - BOOL force = FALSE; - - ntfs_log_set_handler(ntfs_log_handler_outerr); - - parse_options(argc, argv); - - if (!ntfs_check_if_mounted(opt.volume, &mnt_flags)) { - if ((mnt_flags & NTFS_MF_MOUNTED) && - !(mnt_flags & NTFS_MF_READONLY) && !force) { - ntfs_log_error("Refusing to operate on read-write " - "mounted device %s.\n", opt.volume); - exit(1); - } - } else - ntfs_log_perror("Failed to determine whether %s is mounted", - opt.volume); - /* Attempt a full mount first. */ - ntfs_log_info("Mounting volume... "); - vol = ntfs_mount(opt.volume, 0); - if (vol) { - ntfs_log_info(OK); - ntfs_log_info("Processing of $MFT and $MFTMirr completed " - "successfully.\n"); - } else { - ntfs_log_info(FAILED); - exit(1); /* XXX remove before use */ - if (fix_mount() < 0) - exit(1); - vol = ntfs_mount(opt.volume, 0); - if (!vol) { - ntfs_log_perror("Remount failed"); - exit(1); - } - } - /* So the unmount does not clear it again. */ - NVolSetWasDirty(vol); - /* Check NTFS version is ok for us (in $Volume) */ - ntfs_log_info("NTFS volume version is %i.%i.\n", vol->major_ver, - vol->minor_ver); - if (ntfs_version_is_supported(vol)) { - ntfs_log_error("Error: Unknown NTFS version.\n"); - goto error_exit; - } - if (vol->major_ver >= 3) { - /* - * FIXME: If on NTFS 3.0+, check for presence of the usn - * journal and stamp it if present. - */ - } - /* FIXME: We should be marking the quota out of date, too. */ - /* That's all for now! */ - ntfs_log_info("NTFS partition %s was processed successfully.\n", - vol->u.dev->d_name); - /* Set return code to 0. */ - ret = 0; -error_exit: - if (ntfs_umount(vol, 0)) - ntfs_umount(vol, 1); - return ret; -} - diff --git a/usr/src/cmd/ntfsprogs/ntfsinfo.c b/usr/src/cmd/ntfsprogs/ntfsinfo.c deleted file mode 100644 index 8791d57351..0000000000 --- a/usr/src/cmd/ntfsprogs/ntfsinfo.c +++ /dev/null @@ -1,2305 +0,0 @@ -/** - * ntfsinfo - Part of the Linux-NTFS project. - * - * Copyright (c) 2002-2004 Matthew J. Fanto - * Copyright (c) 2002-2006 Anton Altaparmakov - * Copyright (c) 2002-2005 Richard Russon - * Copyright (c) 2003-2006 Szabolcs Szakacsits - * Copyright (c) 2004-2005 Yuval Fledel - * Copyright (c) 2004-2007 Yura Pakhuchiy - * Copyright (c) 2005 Cristian Klein - * - * This utility will dump a file's attributes. - * - * 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 Linux-NTFS - * distribution in the file COPYING); if not, write to the Free Software - * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -/* - * TODO LIST: - * - Better error checking. (focus on ntfs_dump_volume) - * - Comment things better. - * - More things at verbose mode. - * - Dump ACLs when security_id exists (NTFS 3+ only). - * - Clean ups. - * - Internationalization. - * - Add more Indexed Attr Types. - * - Make formatting look more like www.flatcap.org/ntfs/info - * - * Still not dumping certain attributes. Need to find the best - * way to output some of these attributes. - * - * Still need to do: - * $REPARSE_POINT/$SYMBOLIC_LINK - * $LOGGED_UTILITY_STREAM - */ - -#include "config.h" - -#ifdef HAVE_STDIO_H -#include <stdio.h> -#endif -#ifdef HAVE_STDLIB_H -#include <stdlib.h> -#endif -#ifdef HAVE_STRING_H -#include <string.h> -#endif -#ifdef HAVE_TIME_H -#include <time.h> -#endif -#ifdef HAVE_GETOPT_H -#include <getopt.h> -#endif -#ifdef HAVE_ERRNO_H -#include <errno.h> -#endif - -#include "compat.h" -#include "types.h" -#include "mft.h" -#include "attrib.h" -#include "layout.h" -#include "inode.h" -#include "index.h" -#include "utils.h" -#include "security.h" -#include "mst.h" -#include "dir.h" -#include "ntfstime.h" -#include "version.h" -#include "support.h" - -static const char *EXEC_NAME = "ntfsinfo"; - -static struct options { - const char *device; /* Device/File to work with */ - const char *filename; /* Resolve this filename to mft number */ - s64 inode; /* Info for this inode */ - int debug; /* Debug output */ - int quiet; /* Less output */ - int verbose; /* Extra output */ - int force; /* Override common sense */ - int notime; /* Don't report timestamps at all */ - int mft; /* Dump information about the volume as well */ -} opts; - -/** - * version - Print version information about the program - * - * Print a copyright statement and a brief description of the program. - * - * Return: none - */ -static void version(void) -{ - printf("\n%s v%s (libntfs %s) - Display information about an NTFS " - "Volume.\n\n", EXEC_NAME, VERSION, - ntfs_libntfs_version()); - printf("Copyright (c)\n"); - printf(" 2002-2004 Matthew J. Fanto\n"); - printf(" 2002-2006 Anton Altaparmakov\n"); - printf(" 2002-2005 Richard Russon\n"); - printf(" 2003-2006 Szabolcs Szakacsits\n"); - printf(" 2003 Leonard NorrgÃ¥rd\n"); - printf(" 2004-2005 Yuval Fledel\n"); - printf(" 2004-2007 Yura Pakhuchiy\n"); - printf("\n%s\n%s%s\n", ntfs_gpl, ntfs_bugs, ntfs_home); -} - -/** - * usage - Print a list of the parameters to the program - * - * Print a list of the parameters and options for the program. - * - * Return: none - */ -static void usage(void) -{ - printf("\nUsage: %s [options] device\n" - " -i, --inode NUM Display information about this inode\n" - " -F, --file FILE Display information about this file (absolute path)\n" - " -m, --mft Dump information about the volume\n" - " -t, --notime Don't report timestamps\n" - "\n" - " -f, --force Use less caution\n" - " -q, --quiet Less output\n" - " -v, --verbose More output\n" - " -V, --version Display version information\n" - " -h, --help Display this help\n" -#ifdef DEBUG - " -d, --debug Show debug information\n" -#endif - "\n", - EXEC_NAME); - printf("%s%s\n", ntfs_bugs, ntfs_home); -} - -/** - * parse_options - Read and validate the programs command line - * - * Read the command line, verify the syntax and parse the options. - * This function is very long, but quite simple. - * - * Return: 1 Success - * 0 Error, one or more problems - */ -static int parse_options(int argc, char *argv[]) -{ - static const char *sopt = "-:dfhi:F:mqtTvV"; - static const struct option lopt[] = { -#ifdef DEBUG - { "debug", no_argument, NULL, 'd' }, -#endif - { "force", no_argument, NULL, 'f' }, - { "help", no_argument, NULL, 'h' }, - { "inode", required_argument, NULL, 'i' }, - { "file", required_argument, NULL, 'F' }, - { "quiet", no_argument, NULL, 'q' }, - { "verbose", no_argument, NULL, 'v' }, - { "version", no_argument, NULL, 'V' }, - { "notime", no_argument, NULL, 'T' }, - { "mft", no_argument, NULL, 'm' }, - { NULL, 0, NULL, 0 } - }; - - int c = -1; - int err = 0; - int ver = 0; - int help = 0; - int levels = 0; - - opterr = 0; /* We'll handle the errors, thank you. */ - - opts.inode = -1; - opts.filename = NULL; - - while ((c = getopt_long(argc, argv, sopt, lopt, NULL)) != -1) { - switch (c) { - case 1: - if (!opts.device) - opts.device = optarg; - else - err++; - break; - case 'd': - opts.debug++; - break; - case 'i': - if ((opts.inode != -1) || - (!utils_parse_size(optarg, &opts.inode, FALSE))) { - err++; - } - break; - case 'F': - if (opts.filename == NULL) { - /* The inode can not be resolved here, - store the filename */ - opts.filename = argv[optind-1]; - } else { - /* "-F" can't appear more than once */ - err++; - } - break; - case 'f': - opts.force++; - break; - case 'h': - help++; - break; - case 'q': - opts.quiet++; - ntfs_log_clear_levels(NTFS_LOG_LEVEL_QUIET); - break; - case 't': - opts.notime++; - break; - case 'T': - /* 'T' is deprecated, notify */ - ntfs_log_error("Option 'T' is deprecated, it was " - "replaced by 't'.\n"); - err++; - break; - case 'v': - opts.verbose++; - ntfs_log_set_levels(NTFS_LOG_LEVEL_VERBOSE); - break; - case 'V': - ver++; - break; - case 'm': - opts.mft++; - break; - case '?': - if (optopt=='?') { - help++; - continue; - } - if (ntfs_log_parse_option(argv[optind-1])) - continue; - ntfs_log_error("Unknown option '%s'.\n", - argv[optind-1]); - err++; - break; - case ':': - ntfs_log_error("Option '%s' requires an " - "argument.\n", argv[optind-1]); - err++; - break; - default: - ntfs_log_error("Unhandled option case: %d.\n", c); - err++; - break; - } - } - - /* Make sure we're in sync with the log levels */ - levels = ntfs_log_get_levels(); - if (levels & NTFS_LOG_LEVEL_VERBOSE) - opts.verbose++; - if (!(levels & NTFS_LOG_LEVEL_QUIET)) - opts.quiet++; - - if (help || ver) { - opts.quiet = 0; - } else { - if (opts.device == NULL) { - if (argc > 1) - ntfs_log_error("You must specify exactly one " - "device.\n"); - err++; - } - - if ((opts.inode == -1) && (opts.filename == NULL) && !opts.mft) { - if (argc > 1) - ntfs_log_error("You must specify an inode to " - "learn about.\n"); - err++; - } - - if (opts.quiet && opts.verbose) { - ntfs_log_error("You may not use --quiet and --verbose " - "at the same time.\n"); - err++; - } - - if ((opts.inode != -1) && (opts.filename != NULL)) { - if (argc > 1) - ntfs_log_error("You may not specify --inode " - "and --file together.\n"); - err++; - } - - } - -#ifdef DEBUG - if (!opts.debug) - if (!freopen("/dev/null", "w", stderr)) { - ntfs_log_perror("Failed to freopen stderr to /dev/null"); - exit(1); - } -#endif - - if (ver) - version(); - if (help || err) - usage(); - - return (!err && !help && !ver); -} - - -/* *************** utility functions ******************** */ -/** - * ntfsinfo_time_to_str() - - * @sle_ntfs_clock: on disk time format in 100ns units since 1st jan 1601 - * in little-endian format - * - * Return char* in a format 'Thu Jan 1 00:00:00 1970'. - * No need to free the returned memory. - * - * Example of usage: - * char *time_str = ntfsinfo_time_to_str( - * sle64_to_cpu(standard_attr->creation_time)); - * printf("\tFile Creation Time:\t %s", time_str); - */ -static char *ntfsinfo_time_to_str(const sle64 sle_ntfs_clock) -{ - time_t unix_clock = ntfs2utc(sle_ntfs_clock); - return ctime(&unix_clock); -} - -/** - * ntfs_attr_get_name() - * @attr: a valid attribute record - * - * return multi-byte string containing the attribute name if exist. the user - * is then responsible of freeing that memory. - * null if no name exists (attr->name_length==0). no memory allocated. - * null if cannot convert to multi-byte string. errno would contain the - * error id. no memory allocated in that case - */ -static char *ntfs_attr_get_name_mbs(ATTR_RECORD *attr) -{ - ntfschar *ucs_attr_name; - char *mbs_attr_name = NULL; - int mbs_attr_name_size; - - /* Get name in unicode. */ - ucs_attr_name = ntfs_attr_get_name(attr); - /* Convert unicode to printable format. */ - mbs_attr_name_size = ntfs_ucstombs(ucs_attr_name, attr->name_length, - &mbs_attr_name, 0); - if (mbs_attr_name_size > 0) - return mbs_attr_name; - else - return NULL; -} - - -/* *************** functions for dumping global info ******************** */ -/** - * ntfs_dump_volume - dump information about the volume - */ -static void ntfs_dump_volume(ntfs_volume *vol) -{ - printf("Volume Information \n"); - printf("\tName of device: %s\n", vol->u.dev->d_name); - printf("\tDevice state: %lu\n", vol->u.dev->d_state); - printf("\tVolume Name: %s\n", vol->vol_name); - printf("\tVolume State: %lu\n", vol->state); - printf("\tVolume Version: %u.%u\n", vol->major_ver, vol->minor_ver); - printf("\tSector Size: %hu\n", vol->sector_size); - printf("\tCluster Size: %u\n", (unsigned int)vol->cluster_size); - printf("\tVolume Size in Clusters: %lld\n", - (long long)vol->nr_clusters); - - printf("MFT Information \n"); - printf("\tMFT Record Size: %u\n", (unsigned int)vol->mft_record_size); - printf("\tMFT Zone Multiplier: %u\n", vol->mft_zone_multiplier); - printf("\tMFT Data Position: %lld\n", (long long)vol->mft_data_pos); - printf("\tMFT Zone Start: %lld\n", (long long)vol->mft_zone_start); - printf("\tMFT Zone End: %lld\n", (long long)vol->mft_zone_end); - printf("\tMFT Zone Position: %lld\n", (long long)vol->mft_zone_pos); - printf("\tCurrent Position in First Data Zone: %lld\n", - (long long)vol->data1_zone_pos); - printf("\tCurrent Position in Second Data Zone: %lld\n", - (long long)vol->data2_zone_pos); - printf("\tLCN of Data Attribute for FILE_MFT: %lld\n", - (long long)vol->mft_lcn); - printf("\tFILE_MFTMirr Size: %d\n", vol->mftmirr_size); - printf("\tLCN of Data Attribute for File_MFTMirr: %lld\n", - (long long)vol->mftmirr_lcn); - printf("\tSize of Attribute Definition Table: %d\n", - (int)vol->attrdef_len); - - printf("FILE_Bitmap Information \n"); - printf("\tFILE_Bitmap MFT Record Number: %llu\n", - (unsigned long long)vol->lcnbmp_ni->mft_no); - printf("\tState of FILE_Bitmap Inode: %lu\n", vol->lcnbmp_ni->state); - printf("\tLength of Attribute List: %u\n", - (unsigned int)vol->lcnbmp_ni->attr_list_size); - printf("\tAttribute List: %s\n", vol->lcnbmp_ni->attr_list); - printf("\tNumber of Attached Extent Inodes: %d\n", - (int)vol->lcnbmp_ni->nr_extents); - /* FIXME: need to add code for the union if nr_extens != 0, but - i dont know if it will ever != 0 with FILE_Bitmap */ - - printf("FILE_Bitmap Data Attribute Information\n"); - printf("\tDecompressed Runlist: not done yet\n"); - printf("\tBase Inode: %llu\n", - (unsigned long long)vol->lcnbmp_na->ni->mft_no); - printf("\tAttribute Types: not done yet\n"); - //printf("\tAttribute Name: %s\n", vol->lcnbmp_na->name); - printf("\tAttribute Name Length: %u\n", - (unsigned int)vol->lcnbmp_na->name_len); - printf("\tAttribute State: %lu\n", vol->lcnbmp_na->state); - printf("\tAttribute Allocated Size: %lld\n", - (long long)vol->lcnbmp_na->allocated_size); - printf("\tAttribute Data Size: %lld\n", - (long long)vol->lcnbmp_na->data_size); - printf("\tAttribute Initialized Size: %lld\n", - (long long)vol->lcnbmp_na->initialized_size); - printf("\tAttribute Compressed Size: %lld\n", - (long long)vol->lcnbmp_na->compressed_size); - printf("\tCompression Block Size: %u\n", - (unsigned int)vol->lcnbmp_na->compression_block_size); - printf("\tCompression Block Size Bits: %u\n", - vol->lcnbmp_na->compression_block_size_bits); - printf("\tCompression Block Clusters: %u\n", - vol->lcnbmp_na->compression_block_clusters); - - //TODO: Still need to add a few more attributes -} - -/** - * ntfs_dump_flags - Dump flags for STANDARD_INFORMATION and FILE_NAME. - * @type: dump flags for this attribute type - * @flags: flags for dumping - */ -static void ntfs_dump_flags(const char *indent, ATTR_TYPES type, le32 flags) -{ - printf("%sFile attributes:\t", indent); - if (flags & FILE_ATTR_READONLY) { - printf(" READONLY"); - flags &= ~FILE_ATTR_READONLY; - } - if (flags & FILE_ATTR_HIDDEN) { - printf(" HIDDEN"); - flags &= ~FILE_ATTR_HIDDEN; - } - if (flags & FILE_ATTR_SYSTEM) { - printf(" SYSTEM"); - flags &= ~FILE_ATTR_SYSTEM; - } - if (flags & FILE_ATTR_DIRECTORY) { - printf(" DIRECTORY"); - flags &= ~FILE_ATTR_DIRECTORY; - } - if (flags & FILE_ATTR_ARCHIVE) { - printf(" ARCHIVE"); - flags &= ~FILE_ATTR_ARCHIVE; - } - if (flags & FILE_ATTR_DEVICE) { - printf(" DEVICE"); - flags &= ~FILE_ATTR_DEVICE; - } - if (flags & FILE_ATTR_NORMAL) { - printf(" NORMAL"); - flags &= ~FILE_ATTR_NORMAL; - } - if (flags & FILE_ATTR_TEMPORARY) { - printf(" TEMPORARY"); - flags &= ~FILE_ATTR_TEMPORARY; - } - if (flags & FILE_ATTR_SPARSE_FILE) { - printf(" SPARSE_FILE"); - flags &= ~FILE_ATTR_SPARSE_FILE; - } - if (flags & FILE_ATTR_REPARSE_POINT) { - printf(" REPARSE_POINT"); - flags &= ~FILE_ATTR_REPARSE_POINT; - } - if (flags & FILE_ATTR_COMPRESSED) { - printf(" COMPRESSED"); - flags &= ~FILE_ATTR_COMPRESSED; - } - if (flags & FILE_ATTR_OFFLINE) { - printf(" OFFLINE"); - flags &= ~FILE_ATTR_OFFLINE; - } - if (flags & FILE_ATTR_NOT_CONTENT_INDEXED) { - printf(" NOT_CONTENT_INDEXED"); - flags &= ~FILE_ATTR_NOT_CONTENT_INDEXED; - } - if (flags & FILE_ATTR_ENCRYPTED) { - printf(" ENCRYPTED"); - flags &= ~FILE_ATTR_ENCRYPTED; - } - /* We know that FILE_ATTR_I30_INDEX_PRESENT only exists on $FILE_NAME, - and in case we are wrong, let it appear as UNKNOWN */ - if (type == AT_FILE_NAME) { - if (flags & FILE_ATTR_I30_INDEX_PRESENT) { - printf(" I30_INDEX"); - flags &= ~FILE_ATTR_I30_INDEX_PRESENT; - } - } - if (flags & FILE_ATTR_VIEW_INDEX_PRESENT) { - printf(" VIEW_INDEX"); - flags &= ~FILE_ATTR_VIEW_INDEX_PRESENT; - } - if (flags) - printf(" UNKNOWN: 0x%08x", (unsigned int)le32_to_cpu(flags)); - /* Print all the flags in hex. */ - printf(" (0x%08x)\n", (unsigned)le32_to_cpu(flags)); -} - -/** - * ntfs_dump_namespace - */ -static void ntfs_dump_namespace(const char *indent, u8 file_name_type) -{ - const char *mbs_file_type; - - /* name space */ - switch (file_name_type) { - case FILE_NAME_POSIX: - mbs_file_type = "POSIX"; - break; - case FILE_NAME_WIN32: - mbs_file_type = "Win32"; - break; - case FILE_NAME_DOS: - mbs_file_type = "DOS"; - break; - case FILE_NAME_WIN32_AND_DOS: - mbs_file_type = "Win32 & DOS"; - break; - default: - mbs_file_type = "(unknown)"; - } - printf("%sNamespace:\t\t %s\n", indent, mbs_file_type); -} - -/* *************** functions for dumping attributes ******************** */ -/** - * ntfs_dump_standard_information - */ -static void ntfs_dump_attr_standard_information(ATTR_RECORD *attr) -{ - STANDARD_INFORMATION *standard_attr = NULL; - u32 value_length; - - standard_attr = (STANDARD_INFORMATION*)((char *)attr + - le16_to_cpu(attr->u.res.value_offset)); - - /* time conversion stuff */ - if (!opts.notime) { - char *ntfs_time_str = NULL; - - ntfs_time_str = ntfsinfo_time_to_str(standard_attr->creation_time); - printf("\tFile Creation Time:\t %s",ntfs_time_str); - - ntfs_time_str = ntfsinfo_time_to_str( - standard_attr->last_data_change_time); - printf("\tFile Altered Time:\t %s",ntfs_time_str); - - ntfs_time_str = ntfsinfo_time_to_str( - standard_attr->last_mft_change_time); - printf("\tMFT Changed Time:\t %s",ntfs_time_str); - - ntfs_time_str = ntfsinfo_time_to_str(standard_attr->last_access_time); - printf("\tLast Accessed Time:\t %s",ntfs_time_str); - } - ntfs_dump_flags("\t", attr->type, standard_attr->file_attributes); - - value_length = le32_to_cpu(attr->u.res.value_length); - if (value_length == 48) { - /* Only 12 reserved bytes here */ - } else if (value_length == 72) { - printf("\tMaximum versions:\t %u \n", (unsigned int) - le32_to_cpu(standard_attr->u.v30.maximum_versions)); - printf("\tVersion number:\t\t %u \n", (unsigned int) - le32_to_cpu(standard_attr->u.v30.version_number)); - printf("\tClass ID:\t\t %u \n", - (unsigned int)le32_to_cpu(standard_attr->u.v30.class_id)); - printf("\tUser ID:\t\t %u (0x%x)\n", - (unsigned int)le32_to_cpu(standard_attr->u.v30.owner_id), - (unsigned int)le32_to_cpu(standard_attr->u.v30.owner_id)); - printf("\tSecurity ID:\t\t %u (0x%x)\n", - (unsigned int)le32_to_cpu(standard_attr->u.v30.security_id), - (unsigned int)le32_to_cpu(standard_attr->u.v30.security_id)); - printf("\tQuota charged:\t\t %llu (0x%llx)\n", - (unsigned long long) - le64_to_cpu(standard_attr->u.v30.quota_charged), - (unsigned long long) - le64_to_cpu(standard_attr->u.v30.quota_charged)); - printf("\tUpdate Sequence Number:\t %llu (0x%llx)\n", - (unsigned long long) - le64_to_cpu(standard_attr->u.v30.usn), - (unsigned long long) - le64_to_cpu(standard_attr->u.v30.usn)); - } else { - printf("\tSize of STANDARD_INFORMATION is %u (0x%x). It " - "should be either 72 or 48, something is " - "wrong...\n", (unsigned int)value_length, - (unsigned)value_length); - } -} - -static void ntfs_dump_bytes(u8 *buf, int start, int stop) -{ - int i; - - for (i = start; i < stop; i++) { - printf("%02x ", buf[i]); - } -} - -/** - * ntfs_dump_attr_list() - */ -static void ntfs_dump_attr_list(ATTR_RECORD *attr, ntfs_volume *vol) -{ - ATTR_LIST_ENTRY *entry; - u8 *value; - s64 l; - - if (!opts.verbose) - return; - - l = ntfs_get_attribute_value_length(attr); - if (!l) { - ntfs_log_perror("ntfs_get_attribute_value_length failed"); - return; - } - value = ntfs_malloc(l); - if (!value) - return; - - l = ntfs_get_attribute_value(vol, attr, value); - if (!l) { - ntfs_log_perror("ntfs_get_attribute_value failed"); - free(value); - return; - } - printf("\tDumping attribute list:"); - entry = (ATTR_LIST_ENTRY *) value; - for (;(u8 *)entry < (u8 *) value + l; entry = (ATTR_LIST_ENTRY *) - ((u8 *) entry + le16_to_cpu(entry->length))) { - printf("\n"); - printf("\t\tAttribute type:\t0x%x\n", - (unsigned int)le32_to_cpu(entry->type)); - printf("\t\tRecord length:\t%u (0x%x)\n", - (unsigned)le16_to_cpu(entry->length), - (unsigned)le16_to_cpu(entry->length)); - printf("\t\tName length:\t%u (0x%x)\n", - (unsigned)entry->name_length, - (unsigned)entry->name_length); - printf("\t\tName offset:\t%u (0x%x)\n", - (unsigned)entry->name_offset, - (unsigned)entry->name_offset); - printf("\t\tStarting VCN:\t%lld (0x%llx)\n", - (long long)sle64_to_cpu(entry->lowest_vcn), - (unsigned long long) - sle64_to_cpu(entry->lowest_vcn)); - printf("\t\tMFT reference:\t%lld (0x%llx)\n", - (unsigned long long) - MREF_LE(entry->mft_reference), - (unsigned long long) - MREF_LE(entry->mft_reference)); - printf("\t\tInstance:\t%u (0x%x)\n", - (unsigned)le16_to_cpu(entry->instance), - (unsigned)le16_to_cpu(entry->instance)); - printf("\t\tName:\t\t"); - if (entry->name_length) { - char *name = NULL; - int name_size; - - name_size = ntfs_ucstombs(entry->name, - entry->name_length, &name, 0); - - if (name_size > 0) { - printf("%s\n", name); - free(name); - } else - ntfs_log_perror("ntfs_ucstombs failed"); - } else - printf("unnamed\n"); - printf("\t\tPadding:\t"); - ntfs_dump_bytes((u8 *)entry, entry->name_offset + - sizeof(ntfschar) * entry->name_length, - le16_to_cpu(entry->length)); - printf("\n"); - } - free(value); - printf("\tEnd of attribute list reached.\n"); -} - -/** - * ntfs_dump_filename() - */ -static void ntfs_dump_filename(const char *indent, - FILE_NAME_ATTR *file_name_attr) -{ - printf("%sParent directory:\t %lld (0x%llx)\n", indent, - (long long)MREF_LE(file_name_attr->parent_directory), - (long long)MREF_LE(file_name_attr->parent_directory)); - /* time stuff */ - if (!opts.notime) { - char *ntfs_time_str; - - ntfs_time_str = ntfsinfo_time_to_str( - file_name_attr->creation_time); - printf("%sFile Creation Time:\t %s", indent, ntfs_time_str); - - ntfs_time_str = ntfsinfo_time_to_str( - file_name_attr->last_data_change_time); - printf("%sFile Altered Time:\t %s", indent, ntfs_time_str); - - ntfs_time_str = ntfsinfo_time_to_str( - file_name_attr->last_mft_change_time); - printf("%sMFT Changed Time:\t %s", indent, ntfs_time_str); - - ntfs_time_str = ntfsinfo_time_to_str( - file_name_attr->last_access_time); - printf("%sLast Accessed Time:\t %s", indent, ntfs_time_str); - } - /* other basic stuff about the file */ - printf("%sAllocated Size:\t\t %lld (0x%llx)\n", indent, (long long) - sle64_to_cpu(file_name_attr->allocated_size), - (unsigned long long) - sle64_to_cpu(file_name_attr->allocated_size)); - printf("%sData Size:\t\t %lld (0x%llx)\n", indent, - (long long)sle64_to_cpu(file_name_attr->data_size), - (unsigned long long) - sle64_to_cpu(file_name_attr->data_size)); - printf("%sFilename Length:\t %d (0x%x)\n", indent, - (unsigned)file_name_attr->file_name_length, - (unsigned)file_name_attr->file_name_length); - ntfs_dump_flags(indent, AT_FILE_NAME, file_name_attr->file_attributes); - if (file_name_attr->file_attributes & FILE_ATTR_REPARSE_POINT && - file_name_attr->u.reparse_point_tag) - printf("%sReparse point tag:\t 0x%x\n", indent, (unsigned) - le32_to_cpu(file_name_attr->u.reparse_point_tag)); - else if (file_name_attr->u.reparse_point_tag) { - printf("%sEA Length:\t\t %d (0x%x)\n", indent, (unsigned) - le16_to_cpu(file_name_attr->u.s.packed_ea_size), - (unsigned) - le16_to_cpu(file_name_attr->u.s.packed_ea_size)); - if (file_name_attr->u.s.reserved) - printf("%sReserved:\t\t %d (0x%x)\n", indent, - (unsigned) - le16_to_cpu(file_name_attr->u.s.reserved), - (unsigned) - le16_to_cpu(file_name_attr->u.s.reserved)); - } - /* The filename. */ - ntfs_dump_namespace(indent, file_name_attr->file_name_type); - if (file_name_attr->file_name_length > 0) { - /* but first we need to convert the little endian unicode string - into a printable format */ - char *mbs_file_name = NULL; - int mbs_file_name_size; - - mbs_file_name_size = ntfs_ucstombs(file_name_attr->file_name, - file_name_attr->file_name_length,&mbs_file_name,0); - - if (mbs_file_name_size>0) { - printf("%sFilename:\t\t '%s'\n", indent, mbs_file_name); - free(mbs_file_name); - } else { - /* an error occurred, errno holds the reason - notify the user */ - ntfs_log_perror("ntfsinfo error: could not parse file name"); - } - } else { - printf("%sFile Name:\t\t unnamed?!?\n", indent); - } -} - -/** - * ntfs_dump_attr_file_name() - */ -static void ntfs_dump_attr_file_name(ATTR_RECORD *attr) -{ - ntfs_dump_filename("\t", (FILE_NAME_ATTR*)((u8*)attr + - le16_to_cpu(attr->u.res.value_offset))); -} - -/** - * ntfs_dump_object_id - * - * dump the $OBJECT_ID attribute - not present on all systems - */ -static void ntfs_dump_attr_object_id(ATTR_RECORD *attr,ntfs_volume *vol) -{ - OBJECT_ID_ATTR *obj_id_attr = NULL; - - obj_id_attr = (OBJECT_ID_ATTR *)((u8*)attr + - le16_to_cpu(attr->u.res.value_offset)); - - if (vol->major_ver >= 3.0) { - u32 value_length; - char printable_GUID[37]; - - value_length = le32_to_cpu(attr->u.res.value_length); - - /* Object ID is mandatory. */ - ntfs_guid_to_mbs(&obj_id_attr->object_id, printable_GUID); - printf("\tObject ID:\t\t %s\n", printable_GUID); - - /* Dump Birth Volume ID. */ - if ((value_length > sizeof(GUID)) && !ntfs_guid_is_zero( - &obj_id_attr->u.s.birth_volume_id)) { - ntfs_guid_to_mbs(&obj_id_attr->u.s.birth_volume_id, - printable_GUID); - printf("\tBirth Volume ID:\t\t %s\n", printable_GUID); - } else - printf("\tBirth Volume ID:\t missing\n"); - - /* Dumping Birth Object ID */ - if ((value_length > sizeof(GUID)) && !ntfs_guid_is_zero( - &obj_id_attr->u.s.birth_object_id)) { - ntfs_guid_to_mbs(&obj_id_attr->u.s.birth_object_id, - printable_GUID); - printf("\tBirth Object ID:\t\t %s\n", printable_GUID); - } else - printf("\tBirth Object ID:\t missing\n"); - - /* Dumping Domain_id - reserved for now */ - if ((value_length > sizeof(GUID)) && !ntfs_guid_is_zero( - &obj_id_attr->u.s.domain_id)) { - ntfs_guid_to_mbs(&obj_id_attr->u.s.domain_id, - printable_GUID); - printf("\tDomain ID:\t\t\t %s\n", printable_GUID); - } else - printf("\tDomain ID:\t\t missing\n"); - } else - printf("\t$OBJECT_ID not present. Only NTFS versions > 3.0\n" - "\thave $OBJECT_ID. Your version of NTFS is %d.\n", - vol->major_ver); -} - -/** - * ntfs_dump_acl - * - * given an acl, print it in a beautiful & lovely way. - */ -static void ntfs_dump_acl(const char *prefix, ACL *acl) -{ - unsigned int i; - u16 ace_count; - ACCESS_ALLOWED_ACE *ace; - - printf("%sRevision\t %u\n", prefix, acl->revision); - - /* - * Do not recalculate le16_to_cpu every iteration (minor speedup on - * big-endian machines. - */ - ace_count = le16_to_cpu(acl->ace_count); - - /* initialize 'ace' to the first ace (if any) */ - ace = (ACCESS_ALLOWED_ACE *)((char *)acl + 8); - - /* iterate through ACE's */ - for (i = 1; i <= ace_count; i++) { - const char *ace_type; - char *sid; - - /* set ace_type. */ - switch (ace->type) { - case ACCESS_ALLOWED_ACE_TYPE: - ace_type = "allow"; - break; - case ACCESS_DENIED_ACE_TYPE: - ace_type = "deny"; - break; - case SYSTEM_AUDIT_ACE_TYPE: - ace_type = "audit"; - break; - default: - ace_type = "unknown"; - break; - } - - printf("%sACE:\t\t type:%s flags:0x%x access:0x%x\n", prefix, - ace_type, (unsigned int)ace->flags, - (unsigned int)le32_to_cpu(ace->mask)); - /* get a SID string */ - sid = ntfs_sid_to_mbs(&ace->sid, NULL, 0); - printf("%s\t\t SID: %s\n", prefix, sid); - free(sid); - - /* proceed to next ACE */ - ace = (ACCESS_ALLOWED_ACE *)(((char *)ace) + - le16_to_cpu(ace->size)); - } -} - - -static void ntfs_dump_security_descriptor(SECURITY_DESCRIPTOR_ATTR *sec_desc, - const char *indent) -{ - char *sid; - - printf("%s\tRevision:\t\t %u\n", indent, sec_desc->revision); - - /* TODO: parse the flags */ - printf("%s\tControl:\t\t 0x%04x\n", indent, - le16_to_cpu(sec_desc->control)); - - if (~sec_desc->control & SE_SELF_RELATIVE) { - SECURITY_DESCRIPTOR *sd = (SECURITY_DESCRIPTOR *)sec_desc; - - printf("%s\tOwner SID pointer:\t %p\n", indent, sd->owner); - printf("%s\tGroup SID pointer:\t %p\n", indent, sd->group); - printf("%s\tSACL pointer:\t\t %p\n", indent, sd->sacl); - printf("%s\tDACL pointer:\t\t %p\n", indent, sd->dacl); - - return; - } - - if (sec_desc->owner) { - sid = ntfs_sid_to_mbs((SID *)((char *)sec_desc + - le32_to_cpu(sec_desc->owner)), NULL, 0); - printf("%s\tOwner SID:\t\t %s\n", indent, sid); - free(sid); - } else - printf("%s\tOwner SID:\t\t missing\n", indent); - - if (sec_desc->group) { - sid = ntfs_sid_to_mbs((SID *)((char *)sec_desc + - le32_to_cpu(sec_desc->group)), NULL, 0); - printf("%s\tGroup SID:\t\t %s\n", indent, sid); - free(sid); - } else - printf("%s\tGroup SID:\t\t missing\n", indent); - - printf("%s\tSystem ACL:\t\t ", indent); - if (sec_desc->control & SE_SACL_PRESENT) { - if (sec_desc->control & SE_SACL_DEFAULTED) { - printf("defaulted"); - } - printf("\n"); - ntfs_dump_acl(indent ? "\t\t\t" : "\t\t", - (ACL *)((char *)sec_desc + - le32_to_cpu(sec_desc->sacl))); - } else { - printf("missing\n"); - } - - printf("%s\tDiscretionary ACL:\t ", indent); - if (sec_desc->control & SE_DACL_PRESENT) { - if (sec_desc->control & SE_SACL_DEFAULTED) { - printf("defaulted"); - } - printf("\n"); - ntfs_dump_acl(indent ? "\t\t\t" : "\t\t", - (ACL *)((char *)sec_desc + - le32_to_cpu(sec_desc->dacl))); - } else { - printf("missing\n"); - } -} - -/** - * ntfs_dump_security_descriptor() - * - * dump the security information about the file - */ -static void ntfs_dump_attr_security_descriptor(ATTR_RECORD *attr, ntfs_volume *vol) -{ - SECURITY_DESCRIPTOR_ATTR *sec_desc_attr; - - if (attr->non_resident) { - /* FIXME: We don't handle fragmented mapping pairs case. */ - runlist *rl = ntfs_mapping_pairs_decompress(vol, attr, NULL); - if (rl) { - s64 data_size, bytes_read; - - data_size = sle64_to_cpu(attr->u.nonres.data_size); - sec_desc_attr = ntfs_malloc(data_size); - if (!sec_desc_attr) { - free(rl); - return; - } - bytes_read = ntfs_rl_pread(vol, rl, 0, - data_size, sec_desc_attr); - if (bytes_read != data_size) { - ntfs_log_error("ntfsinfo error: could not " - "read security descriptor\n"); - free(rl); - free(sec_desc_attr); - return; - } - free(rl); - } else { - ntfs_log_error("ntfsinfo error: could not " - "decompress runlist\n"); - return; - } - } else { - sec_desc_attr = (SECURITY_DESCRIPTOR_ATTR *)((u8*)attr + - le16_to_cpu(attr->u.res.value_offset)); - } - - ntfs_dump_security_descriptor(sec_desc_attr, ""); - - if (attr->non_resident) - free(sec_desc_attr); -} - -/** - * ntfs_dump_volume_name() - * - * dump the name of the volume the inode belongs to - */ -static void ntfs_dump_attr_volume_name(ATTR_RECORD *attr) -{ - ntfschar *ucs_vol_name = NULL; - - if (le32_to_cpu(attr->u.res.value_length) > 0) { - char *mbs_vol_name = NULL; - int mbs_vol_name_size; - /* calculate volume name position */ - ucs_vol_name = (ntfschar*)((u8*)attr + - le16_to_cpu(attr->u.res.value_offset)); - /* convert the name to current locale multibyte sequence */ - mbs_vol_name_size = ntfs_ucstombs(ucs_vol_name, - le32_to_cpu(attr->u.res.value_length) / - sizeof(ntfschar), &mbs_vol_name, 0); - - if (mbs_vol_name_size>0) { - /* output the converted name. */ - printf("\tVolume Name:\t\t '%s'\n", mbs_vol_name); - free(mbs_vol_name); - } else - ntfs_log_perror("ntfsinfo error: could not parse " - "volume name"); - } else - printf("\tVolume Name:\t\t unnamed\n"); -} - -/** - * ntfs_dump_volume_information() - * - * dump the information for the volume the inode belongs to - * - */ -static void ntfs_dump_attr_volume_information(ATTR_RECORD *attr) -{ - VOLUME_INFORMATION *vol_information = NULL; - - vol_information = (VOLUME_INFORMATION*)((char *)attr+ - le16_to_cpu(attr->u.res.value_offset)); - - printf("\tVolume Version:\t\t %d.%d\n", vol_information->major_ver, - vol_information->minor_ver); - printf("\tVolume Flags:\t\t "); - if (vol_information->flags & VOLUME_IS_DIRTY) - printf("DIRTY "); - if (vol_information->flags & VOLUME_RESIZE_LOG_FILE) - printf("RESIZE_LOG "); - if (vol_information->flags & VOLUME_UPGRADE_ON_MOUNT) - printf("UPG_ON_MOUNT "); - if (vol_information->flags & VOLUME_MOUNTED_ON_NT4) - printf("MOUNTED_NT4 "); - if (vol_information->flags & VOLUME_DELETE_USN_UNDERWAY) - printf("DEL_USN "); - if (vol_information->flags & VOLUME_REPAIR_OBJECT_ID) - printf("REPAIR_OBJID "); - if (vol_information->flags & VOLUME_CHKDSK_UNDERWAY) - printf("CHKDSK_UNDERWAY "); - if (vol_information->flags & VOLUME_MODIFIED_BY_CHKDSK) - printf("MOD_BY_CHKDSK "); - if (vol_information->flags & VOLUME_FLAGS_MASK) { - printf("(0x%04x)\n", - (unsigned)le16_to_cpu(vol_information->flags)); - } else - printf("none set (0x0000)\n"); - if (vol_information->flags & (~VOLUME_FLAGS_MASK)) - printf("\t\t\t\t Unknown Flags: 0x%04x\n", - le16_to_cpu(vol_information->flags & - (~VOLUME_FLAGS_MASK))); -} - -static ntfschar NTFS_DATA_SDS[5] = { const_cpu_to_le16('$'), - const_cpu_to_le16('S'), const_cpu_to_le16('D'), - const_cpu_to_le16('S'), const_cpu_to_le16('\0') }; - -static void ntfs_dump_sds_entry(SECURITY_DESCRIPTOR_HEADER *sds) -{ - SECURITY_DESCRIPTOR_RELATIVE *sd; - - ntfs_log_verbose("\n"); - ntfs_log_verbose("\t\tHash:\t\t\t 0x%08x\n", - (unsigned)le32_to_cpu(sds->hash)); - ntfs_log_verbose("\t\tSecurity id:\t\t %u (0x%x)\n", - (unsigned)le32_to_cpu(sds->security_id), - (unsigned)le32_to_cpu(sds->security_id)); - ntfs_log_verbose("\t\tOffset:\t\t\t %llu (0x%llx)\n", - (unsigned long long)le64_to_cpu(sds->offset), - (unsigned long long)le64_to_cpu(sds->offset)); - ntfs_log_verbose("\t\tLength:\t\t\t %u (0x%x)\n", - (unsigned)le32_to_cpu(sds->length), - (unsigned)le32_to_cpu(sds->length)); - - sd = (SECURITY_DESCRIPTOR_RELATIVE *)((char *)sds + - sizeof(SECURITY_DESCRIPTOR_HEADER)); - - ntfs_dump_security_descriptor(sd, "\t"); -} - -static void ntfs_dump_sds(ATTR_RECORD *attr, ntfs_inode *ni) -{ - SECURITY_DESCRIPTOR_HEADER *sds, *sd; - ntfschar *name; - int name_len; - s64 data_size; - u64 inode; - - inode = ni->mft_no; - if (ni->nr_extents < 0) - inode = ni->u.base_ni->mft_no; - if (FILE_Secure != inode) - return; - - name_len = attr->name_length; - if (!name_len) - return; - - name = (ntfschar *)((u8 *)attr + le16_to_cpu(attr->name_offset)); - if (!ntfs_names_are_equal(NTFS_DATA_SDS, sizeof(NTFS_DATA_SDS) / 2 - 1, - name, name_len, 0, NULL, 0)) - return; - - sd = sds = ntfs_attr_readall(ni, AT_DATA, name, name_len, &data_size); - if (!sd) { - ntfs_log_perror("Failed to read $SDS attribute"); - return; - } - /* - * FIXME: The right way is based on the indexes, so we couldn't - * miss real entries. For now, dump until it makes sense. - */ - while (sd->length && sd->hash && - le64_to_cpu(sd->offset) < (u64)data_size && - le32_to_cpu(sd->length) < (u64)data_size && - le64_to_cpu(sd->offset) + - le32_to_cpu(sd->length) < (u64)data_size) { - ntfs_dump_sds_entry(sd); - sd = (SECURITY_DESCRIPTOR_HEADER *)((char*)sd + - ((le32_to_cpu(sd->length) + 15) & ~15)); - } - free(sds); -} - -static const char *get_attribute_type_name(le32 type) -{ - switch (type) { - case AT_UNUSED: return "$UNUSED"; - case AT_STANDARD_INFORMATION: return "$STANDARD_INFORMATION"; - case AT_ATTRIBUTE_LIST: return "$ATTRIBUTE_LIST"; - case AT_FILE_NAME: return "$FILE_NAME"; - case AT_OBJECT_ID: return "$OBJECT_ID"; - case AT_SECURITY_DESCRIPTOR: return "$SECURITY_DESCRIPTOR"; - case AT_VOLUME_NAME: return "$VOLUME_NAME"; - case AT_VOLUME_INFORMATION: return "$VOLUME_INFORMATION"; - case AT_DATA: return "$DATA"; - case AT_INDEX_ROOT: return "$INDEX_ROOT"; - case AT_INDEX_ALLOCATION: return "$INDEX_ALLOCATION"; - case AT_BITMAP: return "$BITMAP"; - case AT_REPARSE_POINT: return "$REPARSE_POINT"; - case AT_EA_INFORMATION: return "$EA_INFORMATION"; - case AT_EA: return "$EA"; - case AT_PROPERTY_SET: return "$PROPERTY_SET"; - case AT_LOGGED_UTILITY_STREAM: return "$LOGGED_UTILITY_STREAM"; - case AT_END: return "$END"; - } - - return "$UNKNOWN"; -} - -static const char * ntfs_dump_lcn(LCN lcn) -{ - switch (lcn) { - case LCN_HOLE: - return "<HOLE>\t"; - case LCN_RL_NOT_MAPPED: - return "<RL_NOT_MAPPED>"; - case LCN_ENOENT: - return "<ENOENT>\t"; - case LCN_EINVAL: - return "<EINVAL>\t"; - case LCN_EIO: - return "<EIO>\t"; - default: - ntfs_log_error("Invalid LCN value %llx passed to " - "ntfs_dump_lcn().\n", lcn); - return "???\t"; - } -} - -static void ntfs_dump_attribute_header(ntfs_attr_search_ctx *ctx, - ntfs_volume *vol) -{ - ATTR_RECORD *a = ctx->attr; - - printf("Dumping attribute %s (0x%x) from mft record %lld (0x%llx)\n", - get_attribute_type_name(a->type), - (unsigned)le32_to_cpu(a->type), - (unsigned long long)ctx->ntfs_ino->mft_no, - (unsigned long long)ctx->ntfs_ino->mft_no); - - ntfs_log_verbose("\tAttribute length:\t %u (0x%x)\n", - (unsigned)le32_to_cpu(a->length), - (unsigned)le32_to_cpu(a->length)); - printf("\tResident: \t\t %s\n", a->non_resident ? "No" : "Yes"); - ntfs_log_verbose("\tName length:\t\t %u (0x%x)\n", - (unsigned)a->name_length, (unsigned)a->name_length); - ntfs_log_verbose("\tName offset:\t\t %u (0x%x)\n", - (unsigned)le16_to_cpu(a->name_offset), - (unsigned)le16_to_cpu(a->name_offset)); - - /* Dump the attribute (stream) name */ - if (a->name_length) { - char *attribute_name = NULL; - - attribute_name = ntfs_attr_get_name_mbs(a); - if (attribute_name) { - printf("\tAttribute name:\t\t '%s'\n", attribute_name); - free(attribute_name); - } else - ntfs_log_perror("Error: couldn't parse attribute name"); - } - - /* TODO: parse the flags */ - printf("\tAttribute flags:\t 0x%04x\n", - (unsigned)le16_to_cpu(a->flags)); - printf("\tAttribute instance:\t %u (0x%x)\n", - (unsigned)le16_to_cpu(a->instance), - (unsigned)le16_to_cpu(a->instance)); - - /* Resident attribute */ - if (!a->non_resident) { - printf("\tData size:\t\t %u (0x%x)\n", - (unsigned)le32_to_cpu(a->u.res.value_length), - (unsigned)le32_to_cpu(a->u.res.value_length)); - ntfs_log_verbose("\tData offset:\t\t %u (0x%x)\n", - (unsigned)le16_to_cpu(a->u.res.value_offset), - (unsigned)le16_to_cpu(a->u.res.value_offset)); - /* TODO: parse the flags */ - printf("\tResident flags:\t\t 0x%02x\n", - (unsigned)a->u.res.resident_flags); - ntfs_log_verbose("\tReservedR:\t\t %d (0x%x)\n", - (unsigned)a->u.res.reservedR, (unsigned)a->u.res.reservedR); - return; - } - - /* Non-resident attribute */ - ntfs_log_verbose("\tLowest VCN\t\t %lld (0x%llx)\n", - (long long)sle64_to_cpu(a->u.nonres.lowest_vcn), - (unsigned long long)sle64_to_cpu(a->u.nonres.lowest_vcn)); - ntfs_log_verbose("\tHighest VCN:\t\t %lld (0x%llx)\n", - (long long)sle64_to_cpu(a->u.nonres.highest_vcn), - (unsigned long long)sle64_to_cpu(a->u.nonres.highest_vcn)); - ntfs_log_verbose("\tMapping pairs offset:\t %u (0x%x)\n", - (unsigned)le16_to_cpu(a->u.nonres.mapping_pairs_offset), - (unsigned)le16_to_cpu(a->u.nonres.mapping_pairs_offset)); - printf("\tCompression unit:\t %u (0x%x)\n", - (unsigned)a->u.nonres.compression_unit, - (unsigned)a->u.nonres.compression_unit); - /* TODO: dump the 5 reserved bytes here in verbose mode */ - - if (!a->u.nonres.lowest_vcn) { - printf("\tData size:\t\t %llu (0x%llx)\n", - (long long)sle64_to_cpu(a->u.nonres.data_size), - (unsigned long long)sle64_to_cpu(a->u.nonres.data_size)); - printf("\tAllocated size:\t\t %llu (0x%llx)\n", - (long long)sle64_to_cpu(a->u.nonres.allocated_size), - (unsigned long long) - sle64_to_cpu(a->u.nonres.allocated_size)); - printf("\tInitialized size:\t %llu (0x%llx)\n", - (long long)sle64_to_cpu(a->u.nonres.initialized_size), - (unsigned long long) - sle64_to_cpu(a->u.nonres.initialized_size)); - if (a->u.nonres.compression_unit || a->flags & ATTR_IS_COMPRESSED || - a->flags & ATTR_IS_SPARSE) - printf("\tCompressed size:\t %llu (0x%llx)\n", - (signed long long) - sle64_to_cpu(a->u.nonres.compressed_size), - (signed long long) - sle64_to_cpu(a->u.nonres.compressed_size)); - } - - if (opts.verbose) { - runlist *rl; - - rl = ntfs_mapping_pairs_decompress(vol, a, NULL); - if (rl) { - runlist *rlc = rl; - - // TODO: Switch this to properly aligned hex... - printf("\tRunlist:\tVCN\t\tLCN\t\tLength\n"); - while (rlc->length) { - if (rlc->lcn >= 0) - printf("\t\t\t0x%llx\t\t0x%llx\t\t" - "0x%llx\n", rlc->vcn, - rlc->lcn, rlc->length); - else - printf("\t\t\t0x%llx\t\t%s\t" - "0x%llx\n", rlc->vcn, - ntfs_dump_lcn(rlc->lcn), - rlc->length); - rlc++; - } - free(rl); - } else - ntfs_log_error("Error: couldn't decompress runlist\n"); - } -} - -/** - * ntfs_dump_data_attr() - * - * dump some info about the data attribute if it's metadata - */ -static void ntfs_dump_attr_data(ATTR_RECORD *attr, ntfs_inode *ni) -{ - if (opts.verbose) - ntfs_dump_sds(attr, ni); -} - -typedef enum { - INDEX_ATTR_UNKNOWN, - INDEX_ATTR_DIRECTORY_I30, - INDEX_ATTR_SECURE_SII, - INDEX_ATTR_SECURE_SDH, - INDEX_ATTR_OBJID_O, - INDEX_ATTR_REPARSE_R, - INDEX_ATTR_QUOTA_O, - INDEX_ATTR_QUOTA_Q, -} INDEX_ATTR_TYPE; - -static void ntfs_dump_index_key(INDEX_ENTRY *entry, INDEX_ATTR_TYPE type) -{ - char *sid; - char printable_GUID[37]; - - switch (type) { - case INDEX_ATTR_SECURE_SII: - ntfs_log_verbose("\t\tKey security id:\t %u (0x%x)\n", - (unsigned) - le32_to_cpu(entry->key.sii.security_id), - (unsigned) - le32_to_cpu(entry->key.sii.security_id)); - break; - case INDEX_ATTR_SECURE_SDH: - ntfs_log_verbose("\t\tKey hash:\t\t 0x%08x\n", - (unsigned)le32_to_cpu(entry->key.sdh.hash)); - ntfs_log_verbose("\t\tKey security id:\t %u (0x%x)\n", - (unsigned) - le32_to_cpu(entry->key.sdh.security_id), - (unsigned) - le32_to_cpu(entry->key.sdh.security_id)); - break; - case INDEX_ATTR_OBJID_O: - ntfs_guid_to_mbs(&entry->key.object_id, printable_GUID); - ntfs_log_verbose("\t\tKey GUID:\t\t %s\n", printable_GUID); - break; - case INDEX_ATTR_REPARSE_R: - ntfs_log_verbose("\t\tKey reparse tag:\t 0x%08x\n", (unsigned) - le32_to_cpu(entry->key.reparse.reparse_tag)); - ntfs_log_verbose("\t\tKey file id:\t\t %llu (0x%llx)\n", - (unsigned long long) - le64_to_cpu(entry->key.reparse.file_id), - (unsigned long long) - le64_to_cpu(entry->key.reparse.file_id)); - break; - case INDEX_ATTR_QUOTA_O: - sid = ntfs_sid_to_mbs(&entry->key.sid, NULL, 0); - ntfs_log_verbose("\t\tKey SID:\t\t %s\n", sid); - free(sid); - break; - case INDEX_ATTR_QUOTA_Q: - ntfs_log_verbose("\t\tKey owner id:\t\t %u (0x%x)\n", - (unsigned)le32_to_cpu(entry->key.owner_id), - (unsigned)le32_to_cpu(entry->key.owner_id)); - break; - default: - ntfs_log_verbose("\t\tIndex attr type is UNKNOWN: \t 0x%08x\n", - (unsigned)type); - break; - } -} - -#ifdef __sun -#pragma pack(1) -#endif -typedef union { - SII_INDEX_DATA sii; /* $SII index data in $Secure */ - SDH_INDEX_DATA sdh; /* $SDH index data in $Secure */ - QUOTA_O_INDEX_DATA quota_o; /* $O index data in $Quota */ - QUOTA_CONTROL_ENTRY quota_q; /* $Q index data in $Quota */ -} __attribute__((__packed__)) INDEX_ENTRY_DATA; -#ifdef __sun -#pragma pack() -#endif - -static void ntfs_dump_index_data(INDEX_ENTRY *entry, INDEX_ATTR_TYPE type) -{ - INDEX_ENTRY_DATA *data; - - data = (INDEX_ENTRY_DATA *)((u8 *)entry + - le16_to_cpu(entry->u.s.data_offset)); - - switch (type) { - case INDEX_ATTR_SECURE_SII: - ntfs_log_verbose("\t\tHash:\t\t\t 0x%08x\n", - (unsigned)le32_to_cpu(data->sii.hash)); - ntfs_log_verbose("\t\tSecurity id:\t\t %u (0x%x)\n", - (unsigned)le32_to_cpu(data->sii.security_id), - (unsigned)le32_to_cpu(data->sii.security_id)); - ntfs_log_verbose("\t\tOffset in $SDS:\t\t %llu (0x%llx)\n", - (unsigned long long) - le64_to_cpu(data->sii.offset), - (unsigned long long) - le64_to_cpu(data->sii.offset)); - ntfs_log_verbose("\t\tLength in $SDS:\t\t %u (0x%x)\n", - (unsigned)le32_to_cpu(data->sii.length), - (unsigned)le32_to_cpu(data->sii.length)); - break; - case INDEX_ATTR_SECURE_SDH: - ntfs_log_verbose("\t\tHash:\t\t\t 0x%08x\n", - (unsigned)le32_to_cpu(data->sdh.hash)); - ntfs_log_verbose("\t\tSecurity id:\t\t %u (0x%x)\n", - (unsigned)le32_to_cpu(data->sdh.security_id), - (unsigned)le32_to_cpu(data->sdh.security_id)); - ntfs_log_verbose("\t\tOffset in $SDS:\t\t %llu (0x%llx)\n", - (unsigned long long) - le64_to_cpu(data->sdh.offset), - (unsigned long long) - le64_to_cpu(data->sdh.offset)); - ntfs_log_verbose("\t\tLength in $SDS:\t\t %u (0x%x)\n", - (unsigned)le32_to_cpu(data->sdh.length), - (unsigned)le32_to_cpu(data->sdh.length)); - ntfs_log_verbose("\t\tUnknown (padding):\t 0x%08x\n", - (unsigned)le32_to_cpu(data->sdh.reserved_II)); - break; - case INDEX_ATTR_OBJID_O: { - OBJ_ID_INDEX_DATA *object_id_data; - char printable_GUID[37]; - - object_id_data = (OBJ_ID_INDEX_DATA*)((u8*)entry + - le16_to_cpu(entry->u.s.data_offset)); - ntfs_log_verbose("\t\tMFT Number:\t\t 0x%llx\n", - (unsigned long long) - MREF_LE(object_id_data->mft_reference)); - ntfs_log_verbose("\t\tMFT Sequence Number:\t 0x%x\n", - (unsigned) - MSEQNO_LE(object_id_data->mft_reference)); - ntfs_guid_to_mbs(&object_id_data->u.s.birth_volume_id, - printable_GUID); - ntfs_log_verbose("\t\tBirth volume id GUID:\t %s\n", - printable_GUID); - ntfs_guid_to_mbs(&object_id_data->u.s.birth_object_id, - printable_GUID); - ntfs_log_verbose("\t\tBirth object id GUID:\t %s\n", - printable_GUID); - ntfs_guid_to_mbs(&object_id_data->u.s.domain_id, printable_GUID); - ntfs_log_verbose("\t\tDomain id GUID:\t\t %s\n", - printable_GUID); - } - break; - case INDEX_ATTR_REPARSE_R: - /* TODO */ - break; - case INDEX_ATTR_QUOTA_O: - ntfs_log_verbose("\t\tOwner id:\t\t %u (0x%x)\n", - (unsigned)le32_to_cpu(data->quota_o.owner_id), - (unsigned)le32_to_cpu(data->quota_o.owner_id)); - ntfs_log_verbose("\t\tUnknown:\t\t %u (0x%x)\n", - (unsigned)le32_to_cpu(data->quota_o.unknown), - (unsigned)le32_to_cpu(data->quota_o.unknown)); - break; - case INDEX_ATTR_QUOTA_Q: - ntfs_log_verbose("\t\tVersion:\t\t %u\n", - (unsigned)le32_to_cpu(data->quota_q.version)); - ntfs_log_verbose("\t\tQuota flags:\t\t 0x%08x\n", - (unsigned)le32_to_cpu(data->quota_q.flags)); - ntfs_log_verbose("\t\tBytes used:\t\t %llu (0x%llx)\n", - (unsigned long long) - le64_to_cpu(data->quota_q.bytes_used), - (unsigned long long) - le64_to_cpu(data->quota_q.bytes_used)); - ntfs_log_verbose("\t\tLast changed:\t\t %s", - ntfsinfo_time_to_str( - data->quota_q.change_time)); - ntfs_log_verbose("\t\tThreshold:\t\t %lld (0x%llx)\n", - (unsigned long long) - sle64_to_cpu(data->quota_q.threshold), - (unsigned long long) - sle64_to_cpu(data->quota_q.threshold)); - ntfs_log_verbose("\t\tLimit:\t\t\t %lld (0x%llx)\n", - (unsigned long long) - sle64_to_cpu(data->quota_q.limit), - (unsigned long long) - sle64_to_cpu(data->quota_q.limit)); - ntfs_log_verbose("\t\tExceeded time:\t\t %lld (0x%llx)\n", - (unsigned long long) - sle64_to_cpu(data->quota_q.exceeded_time), - (unsigned long long) - sle64_to_cpu(data->quota_q.exceeded_time)); - if (le16_to_cpu(entry->u.s.data_length) > 48) { - char *sid; - sid = ntfs_sid_to_mbs(&data->quota_q.sid, NULL, 0); - ntfs_log_verbose("\t\tOwner SID:\t\t %s\n", sid); - free(sid); - } - break; - default: - ntfs_log_verbose("\t\tIndex attr type is UNKNOWN: \t 0x%08x\n", - (unsigned)type); - break; - } -} - -/** - * ntfs_dump_index_entries() - * - * dump sequence of index_entries and return number of entries dumped. - */ -static int ntfs_dump_index_entries(INDEX_ENTRY *entry, INDEX_ATTR_TYPE type) -{ - int numb_entries = 1; - while (1) { - if (!opts.verbose) { - if (entry->flags & INDEX_ENTRY_END) - break; - entry = (INDEX_ENTRY *)((u8 *)entry + - le16_to_cpu(entry->length)); - numb_entries++; - continue; - } - ntfs_log_verbose("\t\tEntry length:\t\t %u (0x%x)\n", - (unsigned)le16_to_cpu(entry->length), - (unsigned)le16_to_cpu(entry->length)); - ntfs_log_verbose("\t\tKey length:\t\t %u (0x%x)\n", - (unsigned)le16_to_cpu(entry->key_length), - (unsigned)le16_to_cpu(entry->key_length)); - ntfs_log_verbose("\t\tIndex entry flags:\t 0x%02x\n", - (unsigned)le16_to_cpu(entry->flags)); - - if (entry->flags & INDEX_ENTRY_NODE) - ntfs_log_verbose("\t\tSubnode VCN:\t\t %lld (0x%llx)\n", - ntfs_ie_get_vcn(entry), - ntfs_ie_get_vcn(entry)); - if (entry->flags & INDEX_ENTRY_END) - break; - - switch (type) { - case INDEX_ATTR_DIRECTORY_I30: - ntfs_log_verbose("\t\tFILE record number:\t %llu " - "(0x%llx)\n", (unsigned long long) - MREF_LE(entry->u.indexed_file), - (unsigned long long) - MREF_LE(entry->u.indexed_file)); - ntfs_dump_filename("\t\t", &entry->key.file_name); - break; - default: - ntfs_log_verbose("\t\tData offset:\t\t %u (0x%x)\n", - (unsigned) - le16_to_cpu(entry->u.s.data_offset), - (unsigned) - le16_to_cpu(entry->u.s.data_offset)); - ntfs_log_verbose("\t\tData length:\t\t %u (0x%x)\n", - (unsigned) - le16_to_cpu(entry->u.s.data_length), - (unsigned) - le16_to_cpu(entry->u.s.data_length)); - ntfs_dump_index_key(entry, type); - ntfs_log_verbose("\t\tKey Data:\n"); - ntfs_dump_index_data(entry, type); - break; - } - if (!entry->length) { - ntfs_log_verbose("\tWARNING: Corrupt index entry, " - "skipping the remainder of this index " - "block.\n"); - break; - } - entry = (INDEX_ENTRY*)((u8*)entry + le16_to_cpu(entry->length)); - numb_entries++; - ntfs_log_verbose("\n"); - } - ntfs_log_verbose("\tEnd of index block reached\n"); - return numb_entries; -} - -#define COMPARE_INDEX_NAMES(attr, name) \ - ntfs_names_are_equal((name), sizeof(name) / 2 - 1, \ - (ntfschar*)((char*)(attr) + le16_to_cpu((attr)->name_offset)), \ - (attr)->name_length, 0, NULL, 0) - -static INDEX_ATTR_TYPE get_index_attr_type(ntfs_inode *ni, ATTR_RECORD *attr, - INDEX_ROOT *index_root) -{ - char file_name[64]; - - if (!attr->name_length) - return INDEX_ATTR_UNKNOWN; - - if (index_root->type) { - if (index_root->type == AT_FILE_NAME) - return INDEX_ATTR_DIRECTORY_I30; - else - /* weird, this should be illegal */ - ntfs_log_error("Unknown index attribute type: 0x%0X\n", - index_root->type); - return INDEX_ATTR_UNKNOWN; - } - - if (utils_is_metadata(ni) <= 0) - return INDEX_ATTR_UNKNOWN; - if (utils_inode_get_name(ni, file_name, sizeof(file_name)) <= 0) - return INDEX_ATTR_UNKNOWN; - - if (COMPARE_INDEX_NAMES(attr, NTFS_INDEX_SDH)) - return INDEX_ATTR_SECURE_SDH; - else if (COMPARE_INDEX_NAMES(attr, NTFS_INDEX_SII)) - return INDEX_ATTR_SECURE_SII; - else if (COMPARE_INDEX_NAMES(attr, NTFS_INDEX_SII)) - return INDEX_ATTR_SECURE_SII; - else if (COMPARE_INDEX_NAMES(attr, NTFS_INDEX_Q)) - return INDEX_ATTR_QUOTA_Q; - else if (COMPARE_INDEX_NAMES(attr, NTFS_INDEX_R)) - return INDEX_ATTR_REPARSE_R; - else if (COMPARE_INDEX_NAMES(attr, NTFS_INDEX_O)) { - if (!strcmp(file_name, "/$Extend/$Quota")) - return INDEX_ATTR_QUOTA_O; - else if (!strcmp(file_name, "/$Extend/$ObjId")) - return INDEX_ATTR_OBJID_O; - } - - return INDEX_ATTR_UNKNOWN; -} - -static void ntfs_dump_index_attr_type(INDEX_ATTR_TYPE type) -{ - if (type == INDEX_ATTR_DIRECTORY_I30) - printf("DIRECTORY_I30"); - else if (type == INDEX_ATTR_SECURE_SDH) - printf("SECURE_SDH"); - else if (type == INDEX_ATTR_SECURE_SII) - printf("SECURE_SII"); - else if (type == INDEX_ATTR_OBJID_O) - printf("OBJID_O"); - else if (type == INDEX_ATTR_QUOTA_O) - printf("QUOTA_O"); - else if (type == INDEX_ATTR_QUOTA_Q) - printf("QUOTA_Q"); - else if (type == INDEX_ATTR_REPARSE_R) - printf("REPARSE_R"); - else - printf("UNKNOWN"); - printf("\n"); -} - -static void ntfs_dump_index_header(const char *indent, INDEX_HEADER *idx) -{ - printf("%sEntries Offset:\t\t %u (0x%x)\n", indent, - (unsigned)le32_to_cpu(idx->entries_offset), - (unsigned)le32_to_cpu(idx->entries_offset)); - printf("%sIndex Size:\t\t %u (0x%x)\n", indent, - (unsigned)le32_to_cpu(idx->index_length), - (unsigned)le32_to_cpu(idx->index_length)); - printf("%sAllocated Size:\t\t %u (0x%x)\n", indent, - (unsigned)le32_to_cpu(idx->allocated_size), - (unsigned)le32_to_cpu(idx->allocated_size)); - printf("%sIndex header flags:\t 0x%02x\n", indent, idx->flags); - - /* FIXME: there are 3 reserved bytes here */ -} - -/** - * ntfs_dump_attr_index_root() - * - * dump the index_root attribute - */ -static void ntfs_dump_attr_index_root(ATTR_RECORD *attr, ntfs_inode *ni) -{ - INDEX_ATTR_TYPE type; - INDEX_ROOT *index_root = NULL; - INDEX_ENTRY *entry; - - index_root = (INDEX_ROOT*)((u8*)attr + le16_to_cpu(attr->u.res.value_offset)); - - /* attr_type dumping */ - type = get_index_attr_type(ni, attr, index_root); - printf("\tIndexed Attr Type:\t "); - ntfs_dump_index_attr_type(type); - - /* collation rule dumping */ - printf("\tCollation Rule:\t\t %u (0x%x)\n", - (unsigned)le32_to_cpu(index_root->collation_rule), - (unsigned)le32_to_cpu(index_root->collation_rule)); -/* COLLATION_BINARY, COLLATION_FILE_NAME, COLLATION_UNICODE_STRING, - COLLATION_NTOFS_ULONG, COLLATION_NTOFS_SID, - COLLATION_NTOFS_SECURITY_HASH, COLLATION_NTOFS_ULONGS */ - - printf("\tIndex Block Size:\t %u (0x%x)\n", - (unsigned)le32_to_cpu(index_root->index_block_size), - (unsigned)le32_to_cpu(index_root->index_block_size)); - printf("\tClusters Per Block:\t %u (0x%x)\n", - (unsigned)index_root->clusters_per_index_block, - (unsigned)index_root->clusters_per_index_block); - - ntfs_dump_index_header("\t", &index_root->index); - - entry = (INDEX_ENTRY*)((u8*)index_root + - le32_to_cpu(index_root->index.entries_offset) + 0x10); - ntfs_log_verbose("\tDumping index root:\n"); - printf("\tIndex entries total:\t %d\n", - ntfs_dump_index_entries(entry, type)); -} - -static void ntfs_dump_usa_lsn(const char *indent, MFT_RECORD *mrec) -{ - printf("%sUpd. Seq. Array Off.:\t %u (0x%x)\n", indent, - (unsigned)le16_to_cpu(mrec->usa_ofs), - (unsigned)le16_to_cpu(mrec->usa_ofs)); - printf("%sUpd. Seq. Array Count:\t %u (0x%x)\n", indent, - (unsigned)le16_to_cpu(mrec->usa_count), - (unsigned)le16_to_cpu(mrec->usa_count)); - printf("%sUpd. Seq. Number:\t %u (0x%x)\n", indent, - (unsigned)le16_to_cpup((u16 *)((u8 *)mrec + - le16_to_cpu(mrec->usa_ofs))), - (unsigned)le16_to_cpup((u16 *)((u8 *)mrec + - le16_to_cpu(mrec->usa_ofs)))); - printf("%sLogFile Seq. Number:\t 0x%llx\n", indent, - (unsigned long long)sle64_to_cpu(mrec->lsn)); -} - - -static s32 ntfs_dump_index_block(INDEX_BLOCK *ib, INDEX_ATTR_TYPE type, - u32 ib_size) -{ - INDEX_ENTRY *entry; - - if (ntfs_mst_post_read_fixup((NTFS_RECORD*)ib, ib_size)) { - ntfs_log_perror("Damaged INDX record"); - return -1; - } - ntfs_log_verbose("\tDumping index block:\n"); - if (opts.verbose) - ntfs_dump_usa_lsn("\t\t", (MFT_RECORD*)ib); - - ntfs_log_verbose("\t\tNode VCN:\t\t %lld (0x%llx)\n", - (unsigned long long)sle64_to_cpu(ib->index_block_vcn), - (unsigned long long)sle64_to_cpu(ib->index_block_vcn)); - - entry = (INDEX_ENTRY*)((u8*)ib + - le32_to_cpu(ib->index.entries_offset) + 0x18); - - if (opts.verbose) { - ntfs_dump_index_header("\t\t", &ib->index); - printf("\n"); - } - - return ntfs_dump_index_entries(entry, type); -} - -/** - * ntfs_dump_attr_index_allocation() - * - * dump context of the index_allocation attribute - */ -static void ntfs_dump_attr_index_allocation(ATTR_RECORD *attr, ntfs_inode *ni) -{ - INDEX_ALLOCATION *allocation, *tmp_alloc; - INDEX_ROOT *ir; - INDEX_ATTR_TYPE type; - int total_entries = 0; - int total_indx_blocks = 0; - u8 *bitmap, *byte; - int bit; - ntfschar *name; - u32 name_len; - s64 data_size; - - ir = ntfs_index_root_get(ni, attr); - if (!ir) { - ntfs_log_perror("Failed to read $INDEX_ROOT attribute"); - return; - } - - type = get_index_attr_type(ni, attr, ir); - - name = (ntfschar *)((u8 *)attr + le16_to_cpu(attr->name_offset)); - name_len = attr->name_length; - - byte = bitmap = ntfs_attr_readall(ni, AT_BITMAP, name, name_len, NULL); - if (!byte) { - ntfs_log_perror("Failed to read $BITMAP attribute"); - goto out_index_root; - } - - tmp_alloc = allocation = ntfs_attr_readall(ni, AT_INDEX_ALLOCATION, - name, name_len, &data_size); - if (!tmp_alloc) { - ntfs_log_perror("Failed to read $INDEX_ALLOCATION attribute"); - goto out_bitmap; - } - - bit = 0; - while ((u8 *)tmp_alloc < (u8 *)allocation + data_size) { - if (*byte & (1 << bit)) { - int entries; - - entries = ntfs_dump_index_block(tmp_alloc, type, - le32_to_cpu( - ir->index_block_size)); - if (entries != -1) { - total_entries += entries; - total_indx_blocks++; - ntfs_log_verbose("\tIndex entries:\t\t %d\n", - entries); - } - } - tmp_alloc = (INDEX_ALLOCATION *)((u8 *)tmp_alloc + - le32_to_cpu( - ir->index_block_size)); - bit++; - if (bit > 7) { - bit = 0; - byte++; - } - } - - printf("\tIndex entries total:\t %d\n", total_entries); - printf("\tINDX blocks total:\t %d\n", total_indx_blocks); - - free(allocation); -out_bitmap: - free(bitmap); -out_index_root: - free(ir); -} - -/** - * ntfs_dump_attr_bitmap() - * - * dump the bitmap attribute - */ -static void ntfs_dump_attr_bitmap(ATTR_RECORD *attr __attribute__((unused))) -{ - /* TODO */ -} - -/** - * ntfs_dump_attr_reparse_point() - * - * of ntfs 3.x dumps the reparse_point attribute - */ -static void ntfs_dump_attr_reparse_point(ATTR_RECORD *attr __attribute__((unused))) -{ - /* TODO */ -} - -/** - * ntfs_dump_attr_ea_information() - * - * dump the ea_information attribute - */ -static void ntfs_dump_attr_ea_information(ATTR_RECORD *attr) -{ - EA_INFORMATION *ea_info; - - ea_info = (EA_INFORMATION*)((u8*)attr + - le16_to_cpu(attr->u.res.value_offset)); - printf("\tPacked EA length:\t %u (0x%x)\n", - (unsigned)le16_to_cpu(ea_info->ea_length), - (unsigned)le16_to_cpu(ea_info->ea_length)); - printf("\tNEED_EA count:\t\t %u (0x%x)\n", - (unsigned)le16_to_cpu(ea_info->need_ea_count), - (unsigned)le16_to_cpu(ea_info->need_ea_count)); - printf("\tUnpacked EA length:\t %u (0x%x)\n", - (unsigned)le32_to_cpu(ea_info->ea_query_length), - (unsigned)le32_to_cpu(ea_info->ea_query_length)); -} - -/** - * ntfs_dump_attr_ea() - * - * dump the ea attribute - */ -static void ntfs_dump_attr_ea(ATTR_RECORD *attr, ntfs_volume *vol) -{ - EA_ATTR *ea; - u8 *buf = NULL; - s64 data_size; - - if (attr->non_resident) { - runlist *rl; - - data_size = sle64_to_cpu(attr->u.nonres.data_size); - if (!opts.verbose) - return; - /* FIXME: We don't handle fragmented mapping pairs case. */ - rl = ntfs_mapping_pairs_decompress(vol, attr, NULL); - if (rl) { - s64 bytes_read; - - buf = ntfs_malloc(data_size); - if (!buf) { - free(rl); - return; - } - bytes_read = ntfs_rl_pread(vol, rl, 0, data_size, buf); - if (bytes_read != data_size) { - ntfs_log_perror("ntfs_rl_pread failed"); - free(buf); - free(rl); - return; - } - free(rl); - ea = (EA_ATTR*)buf; - } else { - ntfs_log_perror("ntfs_mapping_pairs_decompress failed"); - return; - } - } else { - data_size = le32_to_cpu(attr->u.res.value_length); - if (!opts.verbose) - return; - ea = (EA_ATTR*)((u8*)attr + le16_to_cpu(attr->u.res.value_offset)); - } - while (1) { - printf("\n\tEA flags:\t\t "); - if (ea->flags) { - if (ea->flags == NEED_EA) - printf("NEED_EA\n"); - else - printf("Unknown (0x%02x)\n", - (unsigned)ea->flags); - } else - printf("NONE\n"); - printf("\tName length:\t %d (0x%x)\n", - (unsigned)ea->name_length, - (unsigned)ea->name_length); - printf("\tValue length:\t %d (0x%x)\n", - (unsigned)le16_to_cpu(ea->value_length), - (unsigned)le16_to_cpu(ea->value_length)); - printf("\tName:\t\t '%s'\n", ea->name); - printf("\tValue:\t\t "); - if (ea->name_length == 11 && - !strncmp((const char*)"SETFILEBITS", - (const char*)ea->name, 11)) - printf("0%o\n", (unsigned)le32_to_cpu(*(le32*) - (ea->name + ea->name_length + 1))); - else - printf("'%s'\n", ea->name + ea->name_length + 1); - if (ea->next_entry_offset) - ea = (EA_ATTR*)((u8*)ea + - le32_to_cpu(ea->next_entry_offset)); - else - break; - if ((u8*)ea - buf >= data_size) - break; - } - free(buf); -} - -/** - * ntfs_dump_attr_property_set() - * - * dump the property_set attribute - */ -static void ntfs_dump_attr_property_set(ATTR_RECORD *attr __attribute__((unused))) -{ - /* TODO */ -} - -static void ntfs_hex_dump(void *buf,unsigned int length); - -/** - * ntfs_dump_attr_logged_utility_stream() - * - * dump the property_set attribute - */ -static void ntfs_dump_attr_logged_utility_stream(ATTR_RECORD *attr, - ntfs_inode *ni) -{ - char *buf; - s64 size; - - if (!opts.verbose) - return; - buf = ntfs_attr_readall(ni, AT_LOGGED_UTILITY_STREAM, - ntfs_attr_get_name(attr), attr->name_length, &size); - if (buf) - ntfs_hex_dump(buf, size); - free(buf); - /* TODO */ -} - -/** - * ntfs_hex_dump - */ -static void ntfs_hex_dump(void *buf,unsigned int length) -{ - unsigned int i=0; - while (i<length) { - unsigned int j; - - /* line start */ - printf("\t%04X ",i); - - /* hex content */ - for (j=i;(j<length) && (j<i+16);j++) { - unsigned char c = *((char *)buf + j); - printf("%02hhX ",c); - } - - /* realign */ - for (;j<i+16;j++) { - printf(" "); - } - - /* char content */ - for (j=i;(j<length) && (j<i+16);j++) { - unsigned char c = *((char *)buf + j); - /* display unprintable chars as '.' */ - if ((c<32) || (c>126)) { - c = '.'; - } - printf("%c",c); - } - - /* end line */ - printf("\n"); - i=j; - } -} - -/** - * ntfs_dump_attr_unknown - */ -static void ntfs_dump_attr_unknown(ATTR_RECORD *attr) -{ - printf("===== Please report this unknown attribute type to %s =====\n", - NTFS_DEV_LIST); - - if (!attr->non_resident) { - /* hex dump */ - printf("\tDumping some of the attribute data:\n"); - ntfs_hex_dump((u8*)attr + le16_to_cpu(attr->u.res.value_offset), - (le32_to_cpu(attr->u.res.value_length) > 128) ? - 128 : le32_to_cpu(attr->u.res.value_length)); - } -} - -/** - * ntfs_dump_inode_general_info - */ -static void ntfs_dump_inode_general_info(ntfs_inode *inode) -{ - MFT_RECORD *mrec = inode->mrec; - le16 inode_flags = mrec->flags; - - printf("Dumping Inode %llu (0x%llx)\n", - (long long)inode->mft_no, - (unsigned long long)inode->mft_no); - - ntfs_dump_usa_lsn("", mrec); - printf("MFT Record Seq. Numb.:\t %u (0x%x)\n", - (unsigned)le16_to_cpu(mrec->sequence_number), - (unsigned)le16_to_cpu(mrec->sequence_number)); - printf("Number of Hard Links:\t %u (0x%x)\n", - (unsigned)le16_to_cpu(mrec->link_count), - (unsigned)le16_to_cpu(mrec->link_count)); - printf("Attribute Offset:\t %u (0x%x)\n", - (unsigned)le16_to_cpu(mrec->attrs_offset), - (unsigned)le16_to_cpu(mrec->attrs_offset)); - - printf("MFT Record Flags:\t "); - if (inode_flags) { - if (MFT_RECORD_IN_USE & inode_flags) { - printf("IN_USE "); - inode_flags &= ~MFT_RECORD_IN_USE; - } - if (MFT_RECORD_IS_DIRECTORY & inode_flags) { - printf("DIRECTORY "); - inode_flags &= ~MFT_RECORD_IS_DIRECTORY; - } - /* The meaning of IS_4 is illusive but not its existence. */ - if (MFT_RECORD_IS_4 & inode_flags) { - printf("IS_4 "); - inode_flags &= ~MFT_RECORD_IS_4; - } - if (MFT_RECORD_IS_VIEW_INDEX & inode_flags) { - printf("VIEW_INDEX "); - inode_flags &= ~MFT_RECORD_IS_VIEW_INDEX; - } - if (inode_flags) - printf("UNKNOWN: 0x%04x", (unsigned)le16_to_cpu( - inode_flags)); - } else { - printf("none"); - } - printf("\n"); - - printf("Bytes Used:\t\t %u (0x%x) bytes\n", - (unsigned)le32_to_cpu(mrec->bytes_in_use), - (unsigned)le32_to_cpu(mrec->bytes_in_use)); - printf("Bytes Allocated:\t %u (0x%x) bytes\n", - (unsigned)le32_to_cpu(mrec->bytes_allocated), - (unsigned)le32_to_cpu(mrec->bytes_allocated)); - - if (mrec->base_mft_record) { - printf("Base MFT Record:\t %llu (0x%llx)\n", - (unsigned long long) - MREF_LE(mrec->base_mft_record), - (unsigned long long) - MREF_LE(mrec->base_mft_record)); - } - printf("Next Attribute Instance: %u (0x%x)\n", - (unsigned)le16_to_cpu(mrec->next_attr_instance), - (unsigned)le16_to_cpu(mrec->next_attr_instance)); - - printf("MFT Padding:\t"); - ntfs_dump_bytes((u8 *)mrec, le16_to_cpu(mrec->usa_ofs) + - 2 * le16_to_cpu(mrec->usa_count), - le16_to_cpu(mrec->attrs_offset)); - printf("\n"); -} - -/** - * ntfs_get_file_attributes - */ -static void ntfs_dump_file_attributes(ntfs_inode *inode) -{ - ntfs_attr_search_ctx *ctx = NULL; - - /* then start enumerating attributes - see ntfs_attr_lookup documentation for detailed explanation */ - ctx = ntfs_attr_get_search_ctx(inode, NULL); - while (!ntfs_attr_lookup(AT_UNUSED, NULL, 0, 0, 0, NULL, 0, ctx)) { - if (ctx->attr->type == AT_END || ctx->attr->type == AT_UNUSED) { - printf("Weird: %s attribute type was found, please " - "report this.\n", - get_attribute_type_name( - ctx->attr->type)); - continue; - } - - ntfs_dump_attribute_header(ctx, inode->vol); - - switch (ctx->attr->type) { - case AT_STANDARD_INFORMATION: - ntfs_dump_attr_standard_information(ctx->attr); - break; - case AT_ATTRIBUTE_LIST: - ntfs_dump_attr_list(ctx->attr, inode->vol); - break; - case AT_FILE_NAME: - ntfs_dump_attr_file_name(ctx->attr); - break; - case AT_OBJECT_ID: - ntfs_dump_attr_object_id(ctx->attr, inode->vol); - break; - case AT_SECURITY_DESCRIPTOR: - ntfs_dump_attr_security_descriptor(ctx->attr, - inode->vol); - break; - case AT_VOLUME_NAME: - ntfs_dump_attr_volume_name(ctx->attr); - break; - case AT_VOLUME_INFORMATION: - ntfs_dump_attr_volume_information(ctx->attr); - break; - case AT_DATA: - ntfs_dump_attr_data(ctx->attr, inode); - break; - case AT_INDEX_ROOT: - ntfs_dump_attr_index_root(ctx->attr, inode); - break; - case AT_INDEX_ALLOCATION: - ntfs_dump_attr_index_allocation(ctx->attr, inode); - break; - case AT_BITMAP: - ntfs_dump_attr_bitmap(ctx->attr); - break; - case AT_REPARSE_POINT: - ntfs_dump_attr_reparse_point(ctx->attr); - break; - case AT_EA_INFORMATION: - ntfs_dump_attr_ea_information(ctx->attr); - break; - case AT_EA: - ntfs_dump_attr_ea(ctx->attr, inode->vol); - break; - case AT_PROPERTY_SET: - ntfs_dump_attr_property_set(ctx->attr); - break; - case AT_LOGGED_UTILITY_STREAM: - ntfs_dump_attr_logged_utility_stream(ctx->attr, inode); - break; - default: - ntfs_dump_attr_unknown(ctx->attr); - } - } - - /* if we exited the loop before we're done - notify the user */ - if (errno != ENOENT) { - ntfs_log_perror("ntfsinfo error: stopped before finished " - "enumerating attributes"); - } else { - printf("End of inode reached\n"); - } - - /* close all data-structures we used */ - ntfs_attr_put_search_ctx(ctx); - ntfs_inode_close(inode); -} - -/** - * main() - Begin here - * - * Start from here. - * - * Return: 0 Success, the program worked - * 1 Error, something went wrong - */ -int main(int argc, char **argv) -{ - ntfs_volume *vol; - - setlinebuf(stdout); - - ntfs_log_set_handler(ntfs_log_handler_outerr); - - if (!parse_options(argc, argv)) { - printf("Failed to parse command line options\n"); - exit(1); - } - - utils_set_locale(); - - vol = utils_mount_volume(opts.device, NTFS_MNT_RDONLY | - (opts.force ? NTFS_MNT_FORCE : 0)); - if (!vol) { - printf("Failed to open '%s'.\n", opts.device); - exit(1); - } - - /* - * if opts.mft is not 0, then we will print out information about - * the volume, such as the sector size and whatnot. - */ - if (opts.mft) - ntfs_dump_volume(vol); - - if ((opts.inode != -1) || opts.filename) { - ntfs_inode *inode; - /* obtain the inode */ - if (opts.filename) { - inode = ntfs_pathname_to_inode(vol, NULL, - opts.filename); - } else { - inode = ntfs_inode_open(vol, MK_MREF(opts.inode, 0)); - } - - /* dump the inode information */ - if (inode) { - /* general info about the inode's mft record */ - ntfs_dump_inode_general_info(inode); - /* dump attributes */ - ntfs_dump_file_attributes(inode); - } else { - /* can't open inode */ - /* - * note: when the specified inode does not exist, either - * EIO or or ESPIPE is returned, we should notify better - * in those cases - */ - ntfs_log_perror("Error loading node"); - } - } - - ntfs_umount(vol, FALSE); - return 0; -} - diff --git a/usr/src/cmd/ntfsprogs/ntfslabel.c b/usr/src/cmd/ntfsprogs/ntfslabel.c deleted file mode 100644 index 6c753015a9..0000000000 --- a/usr/src/cmd/ntfsprogs/ntfslabel.c +++ /dev/null @@ -1,412 +0,0 @@ -/** - * ntfslabel - Part of the Linux-NTFS project. - * - * Copyright (c) 2002 Matthew J. Fanto - * Copyright (c) 2002-2005 Anton Altaparmakov - * Copyright (c) 2002-2003 Richard Russon - * - * This utility will display/change the label on an NTFS partition. - * - * 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 Linux-NTFS - * 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 <stdlib.h> -#endif -#ifdef HAVE_STDIO_H -#include <stdio.h> -#endif -#ifdef HAVE_STRING_H -#include <string.h> -#endif -#ifdef HAVE_ERRNO_H -#include <errno.h> -#endif -#ifdef HAVE_LOCALE_H -#include <locale.h> -#endif -#ifdef HAVE_GETOPT_H -#include <getopt.h> -#endif - -#include "compat.h" -#include "debug.h" -#include "mft.h" -#include "utils.h" -#include "version.h" -#include "logging.h" - -static const char *EXEC_NAME = "ntfslabel"; - -static struct options { - char *device; /* Device/File to work with */ - char *label; /* Set the label to this */ - int quiet; /* Less output */ - int verbose; /* Extra output */ - int force; /* Override common sense */ - int noaction; /* Do not write to disk */ -} opts; - -/** - * version - Print version information about the program - * - * Print a copyright statement and a brief description of the program. - * - * Return: none - */ -static void version(void) -{ - ntfs_log_info("\n%s v%s (libntfs %s) - Display, or set, the label for an " - "NTFS Volume.\n\n", EXEC_NAME, VERSION, - ntfs_libntfs_version()); - ntfs_log_info("Copyright (c)\n"); - ntfs_log_info(" 2002 Matthew J. Fanto\n"); - ntfs_log_info(" 2002-2005 Anton Altaparmakov\n"); - ntfs_log_info(" 2002-2003 Richard Russon\n"); - ntfs_log_info("\n%s\n%s%s\n", ntfs_gpl, ntfs_bugs, ntfs_home); -} - -/** - * usage - Print a list of the parameters to the program - * - * Print a list of the parameters and options for the program. - * - * Return: none - */ -static void usage(void) -{ - ntfs_log_info("\nUsage: %s [options] device [label]\n" - " -n, --no-action Do not write to disk\n" - " -f, --force Use less caution\n" - " -q, --quiet Less output\n" - " -v, --verbose More output\n" - " -V, --version Display version information\n" - " -h, --help Display this help\n\n", - EXEC_NAME); - ntfs_log_info("%s%s\n", ntfs_bugs, ntfs_home); -} - -/** - * parse_options - Read and validate the programs command line - * - * Read the command line, verify the syntax and parse the options. - * This function is very long, but quite simple. - * - * Return: 1 Success - * 0 Error, one or more problems - */ -static int parse_options(int argc, char *argv[]) -{ - static const char *sopt = "-fh?nqvV"; - static const struct option lopt[] = { - { "force", no_argument, NULL, 'f' }, - { "help", no_argument, NULL, 'h' }, - { "no-action", no_argument, NULL, 'n' }, - { "quiet", no_argument, NULL, 'q' }, - { "verbose", no_argument, NULL, 'v' }, - { "version", no_argument, NULL, 'V' }, - { NULL, 0, NULL, 0 }, - }; - - int c = -1; - int err = 0; - int ver = 0; - int help = 0; - int levels = 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 (!err && !opts.device) - opts.device = argv[optind-1]; - else if (!err && !opts.label) - opts.label = argv[optind-1]; - else - err++; - break; - case 'f': - opts.force++; - break; - case 'h': - case '?': - if (strncmp (argv[optind-1], "--log-", 6) == 0) { - if (!ntfs_log_parse_option (argv[optind-1])) - err++; - break; - } - help++; - break; - case 'n': - opts.noaction++; - break; - case 'q': - opts.quiet++; - ntfs_log_clear_levels(NTFS_LOG_LEVEL_QUIET); - break; - case 'v': - opts.verbose++; - ntfs_log_set_levels(NTFS_LOG_LEVEL_VERBOSE); - break; - case 'V': - ver++; - break; - default: - ntfs_log_error("Unknown option '%s'.\n", argv[optind-1]); - err++; - break; - } - } - - /* Make sure we're in sync with the log levels */ - levels = ntfs_log_get_levels(); - if (levels & NTFS_LOG_LEVEL_VERBOSE) - opts.verbose++; - if (!(levels & NTFS_LOG_LEVEL_QUIET)) - opts.quiet++; - - if (help || ver) { - opts.quiet = 0; - } else { - if (opts.device == NULL) { - if (argc > 1) - ntfs_log_error("You must specify a device.\n"); - err++; - } - - if (opts.quiet && opts.verbose) { - ntfs_log_error("You may not use --quiet and --verbose at " - "the same time.\n"); - err++; - } - } - - if (ver) - version(); - if (help || err) - usage(); - - return (!err && !help && !ver); -} - - -/** - * print_label - display the current label of a mounted ntfs partition. - * @dev: device to read the label from - * @mnt_flags: mount flags of the device or 0 if not mounted - * @mnt_point: mount point of the device or NULL - * - * Print the label of the device @dev. - */ -static int print_label(ntfs_volume *vol, unsigned long mnt_flags) -{ - int result = 0; - //XXX significant? - if ((mnt_flags & (NTFS_MF_MOUNTED | NTFS_MF_READONLY)) == - NTFS_MF_MOUNTED) { - ntfs_log_error("%s is mounted read-write, results may be " - "unreliable.\n", opts.device); - result = 1; - } - - ntfs_log_info("%s\n", vol->vol_name); - return result; -} - -/** - * resize_resident_attribute_value - resize a resident attribute - * @m: mft record containing attribute to resize - * @a: attribute record (inside @m) which to resize - * @new_vsize: the new attribute value size to resize the attribute to - * - * Return 0 on success and -1 with errno = ENOSPC if not enough space in the - * mft record. - */ -static int resize_resident_attribute_value(MFT_RECORD *m, ATTR_RECORD *a, - const u32 new_vsize) -{ - int new_alen, new_muse; - - /* New attribute length and mft record bytes used. */ - new_alen = (le16_to_cpu(a->u.res.value_offset) + new_vsize + 7) & ~7; - new_muse = le32_to_cpu(m->bytes_in_use) - le32_to_cpu(a->length) + - new_alen; - /* Check for sufficient space. */ - if ((u32)new_muse > le32_to_cpu(m->bytes_allocated)) { - errno = ENOSPC; - return -1; - } - /* Move attributes behind @a to their new location. */ - memmove((char*)a + new_alen, (char*)a + le32_to_cpu(a->length), - le32_to_cpu(m->bytes_in_use) - ((char*)a - (char*)m) - - le32_to_cpu(a->length)); - /* Adjust @m to reflect change in used space. */ - m->bytes_in_use = cpu_to_le32(new_muse); - /* Adjust @a to reflect new value size. */ - a->length = cpu_to_le32(new_alen); - a->u.res.value_length = cpu_to_le32(new_vsize); - return 0; -} - -/** - * change_label - change the current label on a device - * @dev: device to change the label on - * @mnt_flags: mount flags of the device or 0 if not mounted - * @mnt_point: mount point of the device or NULL - * @label: the new label - * - * Change the label on the device @dev to @label. - */ -static int change_label(ntfs_volume *vol, unsigned long mnt_flags, char *label, BOOL force) -{ - ntfs_attr_search_ctx *ctx; - ntfschar *new_label = NULL; - ATTR_RECORD *a; - int label_len; - int result = 0; - - //XXX significant? - if (mnt_flags & NTFS_MF_MOUNTED) { - /* If not the root fs or mounted read/write, refuse change. */ - if (!(mnt_flags & NTFS_MF_ISROOT) || - !(mnt_flags & NTFS_MF_READONLY)) { - if (!force) { - ntfs_log_error("Refusing to change label on " - "read-%s mounted device %s.\n", - mnt_flags & NTFS_MF_READONLY ? - "only" : "write", opts.device); - return 1; - } - } - } - ctx = ntfs_attr_get_search_ctx(vol->vol_ni, NULL); - if (!ctx) { - ntfs_log_perror("Failed to get attribute search context"); - goto err_out; - } - if (ntfs_attr_lookup(AT_VOLUME_NAME, AT_UNNAMED, 0, 0, 0, NULL, 0, - ctx)) { - if (errno != ENOENT) { - ntfs_log_perror("Lookup of $VOLUME_NAME attribute failed"); - goto err_out; - } - /* The volume name attribute does not exist. Need to add it. */ - a = NULL; - } else { - a = ctx->attr; - if (a->non_resident) { - ntfs_log_error("Error: Attribute $VOLUME_NAME must be " - "resident.\n"); - goto err_out; - } - } - label_len = ntfs_mbstoucs(label, &new_label, 0); - if (label_len == -1) { - ntfs_log_perror("Unable to convert label string to Unicode"); - goto err_out; - } - label_len *= sizeof(ntfschar); - if (label_len > 0x100) { - ntfs_log_error("New label is too long. Maximum %u characters " - "allowed. Truncating excess characters.\n", - (unsigned)(0x100 / sizeof(ntfschar))); - label_len = 0x100; - new_label[label_len / sizeof(ntfschar)] = 0; - } - if (a) { - if (resize_resident_attribute_value(ctx->mrec, a, label_len)) { - ntfs_log_perror("Error resizing resident attribute"); - goto err_out; - } - } else { - /* sizeof(resident attribute record header) == 24 */ - int asize = (24 + label_len + 7) & ~7; - u32 biu = le32_to_cpu(ctx->mrec->bytes_in_use); - if (biu + asize > le32_to_cpu(ctx->mrec->bytes_allocated)) { - errno = ENOSPC; - ntfs_log_perror("Error adding resident attribute"); - goto err_out; - } - a = ctx->attr; - memmove((u8*)a + asize, a, biu - ((u8*)a - (u8*)ctx->mrec)); - ctx->mrec->bytes_in_use = cpu_to_le32(biu + asize); - a->type = AT_VOLUME_NAME; - a->length = cpu_to_le32(asize); - a->non_resident = 0; - a->name_length = 0; - a->name_offset = cpu_to_le16(24); - a->flags = cpu_to_le16(0); - a->instance = ctx->mrec->next_attr_instance; - ctx->mrec->next_attr_instance = cpu_to_le16((le16_to_cpu( - ctx->mrec->next_attr_instance) + 1) & 0xffff); - a->u.res.value_length = cpu_to_le32(label_len); - a->u.res.value_offset = a->name_offset; - a->u.res.resident_flags = 0; - a->u.res.reservedR = 0; - } - memcpy((u8*)a + le16_to_cpu(a->u.res.value_offset), new_label, label_len); - if (!opts.noaction && ntfs_inode_sync(vol->vol_ni)) { - ntfs_log_perror("Error writing MFT Record to disk"); - goto err_out; - } - result = 0; -err_out: - free(new_label); - return result; -} - -/** - * main - Begin here - * - * Start from here. - * - * Return: 0 Success, the program worked - * 1 Error, something went wrong - */ -int main(int argc, char **argv) -{ - unsigned long mnt_flags = 0; - int result = 0; - ntfs_volume *vol; - - ntfs_log_set_handler(ntfs_log_handler_outerr); - - if (!parse_options(argc, argv)) - return 1; - - utils_set_locale(); - - if (!opts.label) - opts.noaction++; - - vol = utils_mount_volume(opts.device, - (opts.noaction ? NTFS_MNT_RDONLY : 0) | - (opts.force ? NTFS_MNT_FORCE : 0)); - if (!vol) - return 1; - - if (opts.label) - result = change_label(vol, mnt_flags, opts.label, opts.force); - else - result = print_label(vol, mnt_flags); - - ntfs_umount(vol, FALSE); - return result; -} - diff --git a/usr/src/cmd/ntfsprogs/ntfsls.c b/usr/src/cmd/ntfsprogs/ntfsls.c deleted file mode 100644 index 9264878ff8..0000000000 --- a/usr/src/cmd/ntfsprogs/ntfsls.c +++ /dev/null @@ -1,719 +0,0 @@ -/** - * ntfsls - Part of the Linux-NTFS project. - * - * Copyright (c) 2003 Lode Leroy - * Copyright (c) 2003-2005 Anton Altaparmakov - * Copyright (c) 2003 Richard Russon - * Copyright (c) 2004 Carmelo Kintana - * Copyright (c) 2004 Giang Nguyen - * - * This utility will list a directory's files. - * - * 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 Linux-NTFS - * 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_STDIO_H -#include <stdio.h> -#endif -#ifdef HAVE_STDLIB_H -#include <stdlib.h> -#endif -#ifdef HAVE_TIME_H -#include <time.h> -#endif -#ifdef HAVE_GETOPT_H -#include <getopt.h> -#endif -#ifdef HAVE_STRING_H -#include <string.h> -#endif - -#include "compat.h" -#include "types.h" -#include "mft.h" -#include "attrib.h" -#include "layout.h" -#include "inode.h" -#include "utils.h" -#include "dir.h" -#include "list.h" -#include "ntfstime.h" -#include "version.h" -#include "logging.h" - -static const char *EXEC_NAME = "ntfsls"; - -/** - * To hold sub-directory information for recursive listing. - * @depth: the level of this dir relative to opts.path - */ -struct dir { - struct list_head list; - ntfs_inode *ni; - char name[MAX_PATH]; - int depth; -}; - -/** - * path_component - to store path component strings - * - * @name: string pointer - * - * NOTE: @name is not directly allocated memory. It simply points to the - * character array name in struct dir. - */ -struct path_component { - struct list_head list; - const char *name; -}; - -/* The list of sub-dirs is like a "horizontal" tree. The root of - * the tree is opts.path, but it is not part of the list because - * that's not necessary. The rules of the list are (in order of - * precedence): - * 1. directories immediately follow their parent. - * 2. siblings are next to one another. - * - * For example, if: - * 1. opts.path is / - * 2. / has 2 sub-dirs: dir1 and dir2 - * 3. dir1 has 2 sub-dirs: dir11 and dir12 - * 4. dir2 has 0 sub-dirs - * then the list will be: - * dummy head -> dir1 -> dir11 -> dir12 -> dir2 - * - * dir_list_insert_pos keeps track of where to insert a sub-dir - * into the list. - */ -static struct list_head *dir_list_insert_pos = NULL; - -/* The global depth relative to opts.path. - * ie: opts.path has depth 0, a sub-dir of opts.path has depth 1 - */ -static int depth = 0; - -static struct options { - char *device; /* Device/File to work with */ - int quiet; /* Less output */ - int verbose; /* Extra output */ - int force; /* Override common sense */ - int all; - int system; - int dos; - int lng; - int inode; - int classify; - int recursive; - const char *path; -} opts; - -typedef struct { - ntfs_volume *vol; -} ntfsls_dirent; - -static int list_dir_entry(ntfsls_dirent * dirent, const ntfschar * name, - const int name_len, const int name_type, - const s64 pos, const MFT_REF mref, - const unsigned dt_type); - -/** - * version - Print version information about the program - * - * Print a copyright statement and a brief description of the program. - * - * Return: none - */ -static void version(void) -{ - printf("\n%s v%s (libntfs %s) - Display information about an NTFS " - "Volume.\n\n", EXEC_NAME, VERSION, - ntfs_libntfs_version()); - printf("Copyright (c) 2003 Lode Leroy\n"); - printf("Copyright (c) 2003-2005 Anton Altaparmakov\n"); - printf("Copyright (c) 2003 Richard Russon\n"); - printf("Copyright (c) 2004 Carmelo Kintana\n"); - printf("Copyright (c) 2004 Giang Nguyen\n"); - printf("\n%s\n%s%s\n", ntfs_gpl, ntfs_bugs, ntfs_home); -} - -/** - * usage - Print a list of the parameters to the program - * - * Print a list of the parameters and options for the program. - * - * Return: none - */ -static void usage(void) -{ - printf("\nUsage: %s [options] device\n" - "\n" - " -a, --all Display all files\n" - " -F, --classify Display classification\n" - " -f, --force Use less caution\n" - " -h, --help Display this help\n" - " -i, --inode Display inode numbers\n" - " -l, --long Display long info\n" - " -p, --path PATH Directory whose contents to list\n" - " -q, --quiet Less output\n" - " -R, --recursive Recursively list subdirectories\n" - " -s, --system Display system files\n" - " -V, --version Display version information\n" - " -v, --verbose More output\n" - " -x, --dos Use short (DOS 8.3) names\n" - "\n", - EXEC_NAME); - - printf("NOTE: If neither -a nor -s is specified, the program defaults to -a.\n\n"); - - printf("%s%s\n", ntfs_bugs, ntfs_home); -} - -/** - * parse_options - Read and validate the programs command line - * - * Read the command line, verify the syntax and parse the options. - * This function is very long, but quite simple. - * - * Return: 1 Success - * 0 Error, one or more problems - */ -static int parse_options(int argc, char *argv[]) -{ - static const char *sopt = "-aFfh?ilp:qRsVvx"; - static const struct option lopt[] = { - { "all", no_argument, NULL, 'a' }, - { "classify", no_argument, NULL, 'F' }, - { "force", no_argument, NULL, 'f' }, - { "help", no_argument, NULL, 'h' }, - { "inode", no_argument, NULL, 'i' }, - { "long", no_argument, NULL, 'l' }, - { "path", required_argument, NULL, 'p' }, - { "recursive", no_argument, NULL, 'R' }, - { "quiet", no_argument, NULL, 'q' }, - { "system", no_argument, NULL, 's' }, - { "version", no_argument, NULL, 'V' }, - { "verbose", no_argument, NULL, 'v' }, - { "dos", no_argument, NULL, 'x' }, - { NULL, 0, NULL, 0 }, - }; - - int c = -1; - int err = 0; - int ver = 0; - int help = 0; - int levels = 0; - - opterr = 0; /* We'll handle the errors, thank you. */ - - memset(&opts, 0, sizeof(opts)); - opts.device = NULL; - opts.path = "/"; - - while ((c = getopt_long(argc, argv, sopt, lopt, NULL)) != -1) { - switch (c) { - case 1: - if (!opts.device) - opts.device = optarg; - else - err++; - break; - case 'p': - opts.path = optarg; - break; - case 'f': - opts.force++; - break; - case 'h': - case '?': - if (strncmp (argv[optind-1], "--log-", 6) == 0) { - if (!ntfs_log_parse_option (argv[optind-1])) - err++; - break; - } - help++; - break; - case 'q': - opts.quiet++; - ntfs_log_clear_levels(NTFS_LOG_LEVEL_QUIET); - break; - case 'v': - opts.verbose++; - ntfs_log_set_levels(NTFS_LOG_LEVEL_VERBOSE); - break; - case 'V': - ver++; - break; - case 'x': - opts.dos = 1; - break; - case 'l': - opts.lng++; - break; - case 'i': - opts.inode++; - break; - case 'F': - opts.classify++; - break; - case 'a': - opts.all++; - break; - case 's': - opts.system++; - break; - case 'R': - opts.recursive++; - break; - default: - ntfs_log_error("Unknown option '%s'.\n", argv[optind - 1]); - err++; - break; - } - } - - /* Make sure we're in sync with the log levels */ - levels = ntfs_log_get_levels(); - if (levels & NTFS_LOG_LEVEL_VERBOSE) - opts.verbose++; - if (!(levels & NTFS_LOG_LEVEL_QUIET)) - opts.quiet++; - - /* defaults to -a if -s is not specified */ - if (!opts.system) - opts.all++; - - if (help || ver) - opts.quiet = 0; - else { - if (opts.device == NULL) { - if (argc > 1) - ntfs_log_error("You must specify exactly one " - "device.\n"); - err++; - } - - if (opts.quiet && opts.verbose) { - ntfs_log_error("You may not use --quiet and --verbose at the " - "same time.\n"); - err++; - } - } - - if (ver) - version(); - if (help || err) - usage(); - - return (!err && !help && !ver); -} - -/** - * free_dir - free one dir - * @tofree: the dir to free - * - * Close the inode and then free the dir - */ -static void free_dir(struct dir *tofree) -{ - if (tofree) { - if (tofree->ni) { - ntfs_inode_close(tofree->ni); - tofree->ni = NULL; - } - free(tofree); - } -} - -/** - * free_dirs - walk the list of dir's and free each of them - * @dir_list: the list_head of any entry in the list - * - * Iterate over @dir_list, calling free_dir on each entry - */ -static void free_dirs(struct list_head *dir_list) -{ - struct dir *tofree = NULL; - struct list_head *walker = NULL; - - if (dir_list) { - list_for_each(walker, dir_list) { - free_dir(tofree); - tofree = list_entry(walker, struct dir, list); - } - - free_dir(tofree); - } -} - -/** - * readdir_recursive - list a directory and sub-directories encountered - * @ni: ntfs inode of the directory to list - * @pos: current position in directory - * @dirent: context for filldir callback supplied by the caller - * - * For each directory, print its path relative to opts.path. List a directory, - * then list each of its sub-directories. - * - * Returns 0 on success or -1 on error. - * - * NOTE: Assumes recursive option. Currently no limit on the depths of - * recursion. - */ -static int readdir_recursive(ntfs_inode * ni, s64 * pos, ntfsls_dirent * dirent) -{ - /* list of dirs to "ls" recursively */ - static struct dir dirs = { - .list = LIST_HEAD_INIT(dirs.list), - .ni = NULL, - .name = {0}, - .depth = 0 - }; - - static struct path_component paths = { - .list = LIST_HEAD_INIT(paths.list), - .name = NULL - }; - - static struct path_component base_comp; - - struct dir *subdir = NULL; - struct dir *tofree = NULL; - struct path_component comp; - struct path_component *tempcomp = NULL; - struct list_head *dir_walker = NULL; - struct list_head *comp_walker = NULL; - s64 pos2 = 0; - int ni_depth = depth; - int result = 0; - - if (list_empty(&dirs.list)) { - base_comp.name = opts.path; - list_add(&base_comp.list, &paths.list); - dir_list_insert_pos = &dirs.list; - printf("%s:\n", opts.path); - } - - depth++; - - result = ntfs_readdir(ni, pos, dirent, (ntfs_filldir_t) list_dir_entry); - - if (result == 0) { - list_add_tail(&comp.list, &paths.list); - - /* for each of ni's sub-dirs: list in this iteration, then - free at the top of the next iteration or outside of loop */ - list_for_each(dir_walker, &dirs.list) { - if (tofree) { - free_dir(tofree); - tofree = NULL; - } - subdir = list_entry(dir_walker, struct dir, list); - - /* subdir is not a subdir of ni */ - if (subdir->depth != ni_depth + 1) - break; - - pos2 = 0; - dir_list_insert_pos = &dirs.list; - if (!subdir->ni) { - subdir->ni = - ntfs_pathname_to_inode(ni->vol, ni, - subdir->name); - - if (!subdir->ni) { - ntfs_log_error - ("ntfsls::readdir_recursive(): cannot get inode from pathname.\n"); - result = -1; - break; - } - } - puts(""); - - comp.name = subdir->name; - - /* print relative path header */ - list_for_each(comp_walker, &paths.list) { - tempcomp = - list_entry(comp_walker, - struct path_component, list); - printf("%s", tempcomp->name); - if (tempcomp != &comp - && *tempcomp->name != PATH_SEP - && (!opts.classify - || tempcomp == &base_comp)) - putchar(PATH_SEP); - } - puts(":"); - - result = readdir_recursive(subdir->ni, &pos2, dirent); - - if (result) - break; - - tofree = subdir; - list_del(dir_walker); - } - - list_del(&comp.list); - } - - if (tofree) - free_dir(tofree); - - /* if at the outer-most readdir_recursive, then clean up */ - if (ni_depth == 0) { - free_dirs(&dirs.list); - } - - depth--; - - return result; -} - -/** - * list_dir_entry - * - * FIXME: Should we print errors as we go along? (AIA) - */ -static int list_dir_entry(ntfsls_dirent * dirent, const ntfschar * name, - const int name_len, const int name_type, - const s64 pos __attribute__((unused)), - const MFT_REF mref, const unsigned dt_type) -{ - char *filename = NULL; - int result = 0; - - struct dir *dir = NULL; - - filename = calloc(1, MAX_PATH); - if (!filename) - return -1; - - if (ntfs_ucstombs(name, name_len, &filename, MAX_PATH) < 0) { - ntfs_log_error("Cannot represent filename in current locale.\n"); - goto free; - } - - result = 0; // These are successful - if ((MREF(mref) < FILE_first_user) && (!opts.system)) - goto free; - if (name_type == FILE_NAME_POSIX && !opts.all) - goto free; - if (((name_type & FILE_NAME_WIN32_AND_DOS) == FILE_NAME_WIN32) && - opts.dos) - goto free; - if (((name_type & FILE_NAME_WIN32_AND_DOS) == FILE_NAME_DOS) && - !opts.dos) - goto free; - if (dt_type == NTFS_DT_DIR && opts.classify) - sprintf(filename + strlen(filename), "/"); - - if (dt_type == NTFS_DT_DIR && opts.recursive - && strcmp(filename, ".") && strcmp(filename, "./") - && strcmp(filename, "..") && strcmp(filename, "../")) - { - dir = (struct dir *)calloc(1, sizeof(struct dir)); - - if (!dir) { - ntfs_log_error("Failed to allocate for subdir.\n"); - result = -1; - goto free; - } - - strcpy(dir->name, filename); - dir->ni = NULL; - dir->depth = depth; - } - - if (!opts.lng) { - if (!opts.inode) - printf("%s\n", filename); - else - printf("%7llu %s\n", (unsigned long long)MREF(mref), - filename); - result = 0; - } else { - s64 filesize = 0; - ntfs_inode *ni; - ntfs_attr_search_ctx *ctx = NULL; - FILE_NAME_ATTR *file_name_attr; - ATTR_RECORD *attr; - time_t ntfs_time; - char t_buf[26]; - - result = -1; // Everything else is bad - - ni = ntfs_inode_open(dirent->vol, mref); - if (!ni) - goto release; - - ctx = ntfs_attr_get_search_ctx(ni, NULL); - if (!ctx) - goto release; - - if (ntfs_attr_lookup(AT_FILE_NAME, AT_UNNAMED, 0, 0, 0, NULL, - 0, ctx)) - goto release; - attr = ctx->attr; - - file_name_attr = (FILE_NAME_ATTR *)((char *)attr + - le16_to_cpu(attr->u.res.value_offset)); - if (!file_name_attr) - goto release; - - ntfs_time = ntfs2utc(file_name_attr->last_data_change_time); - strcpy(t_buf, ctime(&ntfs_time)); - memmove(t_buf+16, t_buf+19, 5); - t_buf[21] = '\0'; - - if (dt_type != NTFS_DT_DIR) { - if (!ntfs_attr_lookup(AT_DATA, AT_UNNAMED, 0, 0, 0, - NULL, 0, ctx)) - filesize = ntfs_get_attribute_value_length( - ctx->attr); - } - - if (opts.inode) - printf("%7llu %8lld %s %s\n", - (unsigned long long)MREF(mref), - (long long)filesize, t_buf + 4, - filename); - else - printf("%8lld %s %s\n", (long long)filesize, t_buf + 4, - filename); - - if (dir) { - dir->ni = ni; - ni = NULL; /* so release does not close inode */ - } - - result = 0; -release: - /* Release attribute search context and close the inode. */ - if (ctx) - ntfs_attr_put_search_ctx(ctx); - if (ni) - ntfs_inode_close(ni); - } - - if (dir) { - if (result == 0) { - list_add(&dir->list, dir_list_insert_pos); - dir_list_insert_pos = &dir->list; - } else { - free(dir); - dir = NULL; - } - } - -free: - free(filename); - return result; -} - -/** - * main - Begin here - * - * Start from here. - * - * Return: 0 Success, the program worked - * 1 Error, parsing mount options failed - * 2 Error, mount attempt failed - * 3 Error, failed to open root directory - * 4 Error, failed to open directory in search path - */ -int main(int argc, char **argv) -{ - s64 pos; - ntfs_volume *vol; - ntfs_inode *ni; - ntfsls_dirent dirent; - - ntfs_log_set_handler(ntfs_log_handler_outerr); - - if (!parse_options(argc, argv)) { - // FIXME: Print error... (AIA) - return 1; - } - - utils_set_locale(); - - vol = utils_mount_volume(opts.device, NTFS_MNT_RDONLY | - (opts.force ? NTFS_MNT_FORCE : 0)); - if (!vol) { - // FIXME: Print error... (AIA) - return 2; - } - - ni = ntfs_pathname_to_inode(vol, NULL, opts.path); - if (!ni) { - // FIXME: Print error... (AIA) - ntfs_umount(vol, FALSE); - return 3; - } - - /* - * We now are at the final path component. If it is a file just - * list it. If it is a directory, list its contents. - */ - pos = 0; - memset(&dirent, 0, sizeof(dirent)); - dirent.vol = vol; - if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) { - if (opts.recursive) - readdir_recursive(ni, &pos, &dirent); - else - ntfs_readdir(ni, &pos, &dirent, - (ntfs_filldir_t) list_dir_entry); - // FIXME: error checking... (AIA) - } else { - ATTR_RECORD *rec; - FILE_NAME_ATTR *attr; - ntfs_attr_search_ctx *ctx; - int space = 4; - ntfschar *name = NULL; - int name_len = 0;; - - ctx = ntfs_attr_get_search_ctx(ni, NULL); - if (!ctx) - return -1; - - while ((rec = find_attribute(AT_FILE_NAME, ctx))) { - /* We know this will always be resident. */ - attr = (FILE_NAME_ATTR *) ((char *) rec + le16_to_cpu(rec->u.res.value_offset)); - - if (attr->file_name_type < space) { - name = attr->file_name; - name_len = attr->file_name_length; - space = attr->file_name_type; - } - } - - list_dir_entry(&dirent, name, name_len, space, pos, ni->mft_no, - NTFS_DT_REG); - // FIXME: error checking... (AIA) - - ntfs_attr_put_search_ctx(ctx); - } - - /* Finished with the inode; release it. */ - ntfs_inode_close(ni); - - ntfs_umount(vol, FALSE); - return 0; -} - diff --git a/usr/src/cmd/ntfsprogs/ntfsresize.c b/usr/src/cmd/ntfsprogs/ntfsresize.c deleted file mode 100644 index fe96836b33..0000000000 --- a/usr/src/cmd/ntfsprogs/ntfsresize.c +++ /dev/null @@ -1,2501 +0,0 @@ -/** - * ntfsresize - Part of the Linux-NTFS project. - * - * Copyright (c) 2002-2006 Szabolcs Szakacsits - * Copyright (c) 2002-2005 Anton Altaparmakov - * Copyright (c) 2002-2003 Richard Russon - * Copyright (c) 2007 Yura Pakhuchiy - * - * This utility will resize an NTFS volume without data loss. - * - * WARNING FOR DEVELOPERS!!! Several external tools grep for text messages - * to control execution thus if you would like to change any message - * then PLEASE think twice before doing so then don't modify it. Thanks! - * - * 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 Linux-NTFS - * 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_UNISTD_H -#include <unistd.h> -#endif -#ifdef HAVE_STDLIB_H -#include <stdlib.h> -#endif -#ifdef HAVE_STDIO_H -#include <stdio.h> -#endif -#ifdef HAVE_STDARG_H -#include <stdarg.h> -#endif -#ifdef HAVE_STRING_H -#include <string.h> -#endif -#ifdef HAVE_ERRNO_H -#include <errno.h> -#endif -#ifdef HAVE_GETOPT_H -#include <getopt.h> -#endif - -#include "compat.h" -#include "debug.h" -#include "types.h" -#include "support.h" -#include "endians.h" -#include "bootsect.h" -#include "device.h" -#include "attrib.h" -#include "volume.h" -#include "mft.h" -#include "bitmap.h" -#include "inode.h" -#include "runlist.h" -#include "utils.h" -#include "version.h" - -static const char *EXEC_NAME = "ntfsresize"; - -static const char *resize_warning_msg = -"WARNING: Every sanity check passed and only the dangerous operations left.\n" -"Make sure that important data has been backed up! Power outage or computer\n" -"crash may result major data loss!\n"; - -static const char *resize_important_msg = -#ifdef __sun -"When booted, Windows will check the file system and may reboot.\n" -"If you are running this from inside parted, STOP reading now.\n" -"Otherwise, you can go on to shrink the device with fdisk or parted.\n" -#else -"You can go on to shrink the device for example with Linux fdisk.\n" -#endif -"IMPORTANT: When recreating the partition, make sure that you\n" -" 1) create it at the same disk sector (use sector as the unit!)\n" -" 2) create it with the same partition type (usually 7, HPFS/NTFS)\n" -" 3) do not make it smaller than the new NTFS filesystem size\n" -" 4) set the bootable flag for the partition if it existed before\n" -"Otherwise you won't be able to access NTFS or can't boot from the disk!\n" -"If you make a mistake and don't have a partition table backup then you\n" -"can recover the partition table by TestDisk or Parted's rescue mode.\n"; - -static const char *invalid_ntfs_msg = -"The device '%s' doesn't have a valid NTFS.\n" -"Maybe you selected the wrong partition? Or the whole disk instead of a\n" -"partition (e.g. /dev/hda, not /dev/hda1)? This error might also occur\n" -"if the disk was incorrectly repartitioned (see the ntfsresize FAQ).\n"; - -static const char *corrupt_volume_msg = -"NTFS is inconsistent. Run chkdsk /f on Windows then reboot it TWICE!\n" -"The usage of the /f parameter is very IMPORTANT! No modification was\n" -"and will be made to NTFS by this software until it gets repaired.\n"; - -static const char *hibernated_volume_msg = -"The NTFS partition is hibernated. Windows must be resumed and turned off\n" -"properly, so resizing could be done safely.\n"; - -static const char *unclean_journal_msg = -"The NTFS journal file is unclean. Please shutdown Windows properly before\n" -"using this software! Note, if you have run chkdsk previously then boot\n" -"Windows again which will automatically initialize the journal correctly.\n"; - -static const char *opened_volume_msg = -"This software has detected that the NTFS volume is already opened by another\n" -"software thus it refuses to progress to preserve data consistency.\n"; - -static const char *bad_sectors_warning_msg = -"****************************************************************************\n" -"* WARNING: The disk has bad sector. This means physical damage on the disk *\n" -"* surface caused by deterioration, manufacturing faults or other reason. *\n" -"* The reliability of the disk may stay stable or degrade fast. We suggest *\n" -"* making a full backup urgently by running 'ntfsclone --rescue ...' then *\n" -"* run 'chkdsk /f /r' on Windows and rebooot it TWICE! Then you can resize *\n" -"* NTFS safely by additionally using the --bad-sectors option of ntfsresize.*\n" -"****************************************************************************\n"; - -static const char *many_bad_sectors_msg = -"***************************************************************************\n" -"* WARNING: The disk has many bad sectors. This means physical damage *\n" -"* on the disk surface caused by deterioration, manufacturing faults or *\n" -"* other reason. We suggest to get a replacement disk as soon as possible. *\n" -"***************************************************************************\n"; - -static struct { - int verbose; - int debug; - int ro_flag; - int force; - int info; - int show_progress; - int badsectors; - s64 bytes; - char *volume; -} opt; - -struct bitmap { - s64 size; - u8 *bm; -}; - -#define NTFS_PROGBAR 0x0001 -#define NTFS_PROGBAR_SUPPRESS 0x0002 - -struct progress_bar { - u64 start; - u64 stop; - int resolution; - int flags; - float unit; -}; - -struct llcn_t { - s64 lcn; /* last used LCN for a "special" file/attr type */ - s64 inode; /* inode using it */ -}; - -#define NTFSCK_PROGBAR 0x0001 - -typedef struct { - ntfs_inode *ni; /* inode being processed */ - ntfs_attr_search_ctx *ctx; /* inode attribute being processed */ - s64 inuse; /* num of clusters in use */ - int multi_ref; /* num of clusters referenced many times */ - int outsider; /* num of clusters outside the volume */ - int show_outsider; /* controls showing the above information */ - int flags; - struct bitmap lcn_bitmap; -} ntfsck_t; - -typedef struct { - ntfs_volume *vol; - ntfs_inode *ni; /* inode being processed */ - s64 new_volume_size; /* in clusters; 0 = --info w/o --size */ - MFT_REF mref; /* mft reference */ - MFT_RECORD *mrec; /* mft record */ - ntfs_attr_search_ctx *ctx; /* inode attribute being processed */ - u64 relocations; /* num of clusters to relocate */ - s64 inuse; /* num of clusters in use */ - runlist mftmir_rl; /* $MFTMirr AT_DATA's new position */ - s64 mftmir_old; /* $MFTMirr AT_DATA's old LCN */ - int dirty_inode; /* some inode data got relocated */ - int shrink; /* shrink = 1, enlarge = 0 */ - s64 badclusters; /* num of physically dead clusters */ - VCN mft_highest_vcn; /* used for relocating the $MFT */ - struct progress_bar progress; - struct bitmap lcn_bitmap; - /* Temporary statistics until all case is supported */ - struct llcn_t last_mft; - struct llcn_t last_mftmir; - struct llcn_t last_multi_mft; - struct llcn_t last_sparse; - struct llcn_t last_compressed; - struct llcn_t last_lcn; - s64 last_unsupp; /* last unsupported cluster */ -} ntfs_resize_t; - -/* FIXME: This, lcn_bitmap and pos from find_free_cluster() will make a cluster - allocation related structure, attached to ntfs_resize_t */ -static s64 max_free_cluster_range = 0; - -#define NTFS_MBYTE (1000 * 1000) - -/* WARNING: don't modify the text, external tools grep for it */ -#define ERR_PREFIX "ERROR" -#define PERR_PREFIX ERR_PREFIX "(%d): " -#define NERR_PREFIX ERR_PREFIX ": " - -#define DIRTY_NONE (0) -#define DIRTY_INODE (1) -#define DIRTY_ATTRIB (2) - -#define NTFS_MAX_CLUSTER_SIZE (65536) - -static s64 rounded_up_division(s64 numer, s64 denom) -{ - return (numer + (denom - 1)) / denom; -} - -/** - * perr_printf - * - * Print an error message. - */ -__attribute__((format(printf, 1, 2))) -static void perr_printf(const char *fmt, ...) -{ - va_list ap; - int eo = errno; - - fprintf(stdout, PERR_PREFIX, eo); - va_start(ap, fmt); - vfprintf(stdout, fmt, ap); - va_end(ap); - fprintf(stdout, ": %s\n", strerror(eo)); - fflush(stdout); - fflush(stderr); -} - -__attribute__((format(printf, 1, 2))) -static void err_printf(const char *fmt, ...) -{ - va_list ap; - - fprintf(stdout, NERR_PREFIX); - va_start(ap, fmt); - vfprintf(stdout, fmt, ap); - va_end(ap); - fflush(stdout); - fflush(stderr); -} - -/** - * err_exit - * - * Print and error message and exit the program. - */ -__attribute__((noreturn)) -__attribute__((format(printf, 1, 2))) -static int err_exit(const char *fmt, ...) -{ - va_list ap; - - fprintf(stdout, NERR_PREFIX); - va_start(ap, fmt); - vfprintf(stdout, fmt, ap); - va_end(ap); - fflush(stdout); - fflush(stderr); - exit(1); -} - -/** - * perr_exit - * - * Print and error message and exit the program - */ -__attribute__((noreturn)) -__attribute__((format(printf, 1, 2))) -static int perr_exit(const char *fmt, ...) -{ - va_list ap; - int eo = errno; - - fprintf(stdout, PERR_PREFIX, eo); - va_start(ap, fmt); - vfprintf(stdout, fmt, ap); - va_end(ap); - printf(": %s\n", strerror(eo)); - fflush(stdout); - fflush(stderr); - exit(1); -} - -/** - * usage - Print a list of the parameters to the program - * - * Print a list of the parameters and options for the program. - * - * Return: none - */ -__attribute__((noreturn)) -static void usage(void) -{ - - printf("\nUsage: %s [OPTIONS] DEVICE\n" - " Resize an NTFS volume non-destructively, safely move any data if needed.\n" - "\n" - " -i, --info Estimate the smallest shrunken size possible\n" - " -s, --size SIZE Resize volume to SIZE[k|M|G] bytes\n" - "\n" - " -n, --no-action Do not write to disk\n" - " -b, --bad-sectors Support disks having bad sectors\n" - " -f, --force Force to progress\n" - " -P, --no-progress-bar Don't show progress bar\n" - " -v, --verbose More output\n" - " -V, --version Display version information\n" - " -h, --help Display this help\n" -#ifdef DEBUG - " -d, --debug Show debug information\n" -#endif - "\n" - " The options -i and -s are mutually exclusive. If both options are\n" - " omitted then the NTFS volume will be enlarged to the DEVICE size.\n" - "\n", EXEC_NAME); - printf("%s%s", ntfs_bugs, ntfs_home); - printf("Ntfsresize FAQ: http://linux-ntfs.sourceforge.net/info/ntfsresize.html\n"); - exit(1); -} - -/** - * proceed_question - * - * Force the user to confirm an action before performing it. - * Copy-paste from e2fsprogs - */ -static void proceed_question(void) -{ - char buf[256]; - const char *short_yes = "yY"; - - fflush(stdout); - fflush(stderr); - printf("Are you sure you want to proceed (y/[n])? "); - buf[0] = 0; - fgets(buf, sizeof(buf), stdin); - if (!strchr(short_yes, buf[0])) { - printf("OK quitting. NO CHANGES have been made to your " - "NTFS volume.\n"); - exit(1); - } -} - -/** - * version - Print version information about the program - * - * Print a copyright statement and a brief description of the program. - * - * Return: none - */ -static void version(void) -{ - printf("\nResize an NTFS Volume, without data loss.\n\n"); - printf("Copyright (c) 2002-2006 Szabolcs Szakacsits\n"); - printf("Copyright (c) 2002-2005 Anton Altaparmakov\n"); - printf("Copyright (c) 2002-2003 Richard Russon\n"); - printf("Copyright (c) 2007 Yura Pakhuchiy\n"); - printf("\n%s\n%s%s", ntfs_gpl, ntfs_bugs, ntfs_home); -} - -/** - * get_new_volume_size - * - * Convert a user-supplied string into a size. Without any suffix the number - * will be assumed to be in bytes. If the number has a suffix of k, M or G it - * will be scaled up by 1000, 1000000, or 1000000000. - */ -static s64 get_new_volume_size(char *s) -{ - s64 size; - char *suffix; - int prefix_kind = 1000; - - size = strtoll(s, &suffix, 10); - if (size <= 0 || errno == ERANGE) - err_exit("Illegal new volume size\n"); - - if (!*suffix) - return size; - - if (strlen(suffix) == 2 && suffix[1] == 'i') - prefix_kind = 1024; - else if (strlen(suffix) > 1) - usage(); - - /* We follow the SI prefixes: - http://physics.nist.gov/cuu/Units/prefixes.html - http://physics.nist.gov/cuu/Units/binary.html - Disk partitioning tools use prefixes as, - k M G - fdisk 2.11x- 2^10 2^20 10^3*2^20 - fdisk 2.11y+ 10^3 10^6 10^9 - cfdisk 10^3 10^6 10^9 - sfdisk 2^10 2^20 - parted 2^10 2^20 (may change) - fdisk (DOS) 2^10 2^20 - */ - /* FIXME: check for overflow */ - switch (*suffix) { - case 'G': - size *= prefix_kind; - case 'M': - size *= prefix_kind; - case 'k': - size *= prefix_kind; - break; - default: - usage(); - } - - return size; -} - -/** - * parse_options - Read and validate the programs command line - * - * Read the command line, verify the syntax and parse the options. - * This function is very long, but quite simple. - * - * Return: 1 Success - * 0 Error, one or more problems - */ -static int parse_options(int argc, char **argv) -{ - static const char *sopt = "-bdfhinPs:vV"; - static const struct option lopt[] = { - { "bad-sectors",no_argument, NULL, 'b' }, -#ifdef DEBUG - { "debug", no_argument, NULL, 'd' }, -#endif - { "force", no_argument, NULL, 'f' }, - { "help", no_argument, NULL, 'h' }, - { "info", no_argument, NULL, 'i' }, - { "no-action", no_argument, NULL, 'n' }, - { "no-progress-bar", no_argument, NULL, 'P' }, - { "size", required_argument, NULL, 's' }, - { "verbose", no_argument, NULL, 'v' }, - { "version", no_argument, NULL, 'V' }, - { NULL, 0, NULL, 0 } - }; - - int c; - int err = 0; - int ver = 0; - int help = 0; - - memset(&opt, 0, sizeof(opt)); - opt.show_progress = 1; - - while ((c = getopt_long(argc, argv, sopt, lopt, NULL)) != -1) { - switch (c) { - case 1: /* A non-option argument */ - if (!err && !opt.volume) - opt.volume = argv[optind-1]; - else - err++; - break; - case 'b': - opt.badsectors++; - break; - case 'd': - opt.debug++; - break; - case 'f': - opt.force++; - break; - case 'h': - case '?': - help++; - break; - case 'i': - opt.info++; - break; - case 'n': - opt.ro_flag = NTFS_MNT_RDONLY; - break; - case 'P': - opt.show_progress = 0; - break; - case 's': - if (!err && (opt.bytes == 0)) - opt.bytes = get_new_volume_size(optarg); - else - err++; - break; - case 'v': - opt.verbose++; - ntfs_log_set_levels(NTFS_LOG_LEVEL_VERBOSE); - break; - case 'V': - ver++; - break; - default: - if (optopt == 's') { - printf("Option '%s' requires an argument.\n", argv[optind-1]); - } else { - printf("Unknown option '%s'.\n", argv[optind-1]); - } - err++; - break; - } - } - - if (!help && !ver) { - if (opt.volume == NULL) { - if (argc > 1) - printf("You must specify exactly one device.\n"); - err++; - } - if (opt.info) { - opt.ro_flag = NTFS_MNT_RDONLY; - if (opt.bytes) { - printf(NERR_PREFIX "Options --info and --size " - "can't be used together.\n"); - usage(); - } - } - } - - /* Redirect stderr to stdout, note fflush()es are essential! */ - fflush(stdout); - fflush(stderr); - if (dup2(STDOUT_FILENO, STDERR_FILENO) == -1) - perr_exit("Failed to redirect stderr to stdout"); - fflush(stdout); - fflush(stderr); - -#ifdef DEBUG - if (!opt.debug) - if (!freopen("/dev/null", "w", stderr)) - perr_exit("Failed to redirect stderr to /dev/null"); -#endif - - if (ver) - version(); - if (help || err) - usage(); - - return (!err && !help && !ver); -} - -static void print_advise(ntfs_volume *vol, s64 supp_lcn) -{ - s64 old_b, new_b, freed_b, old_mb, new_mb, freed_mb; - - old_b = vol->nr_clusters * vol->cluster_size; - old_mb = rounded_up_division(old_b, NTFS_MBYTE); - - /* Take the next supported cluster (free or relocatable) - plus reserve a cluster for the backup boot sector */ - supp_lcn += 2; - - if (supp_lcn > vol->nr_clusters) { - err_printf("Very rare fragmentation type detected. " - "Sorry, it's not supported yet.\n" - "Try to defragment your NTFS, perhaps it helps.\n"); - exit(1); - } - - new_b = supp_lcn * vol->cluster_size; - new_mb = rounded_up_division(new_b, NTFS_MBYTE); - freed_b = (vol->nr_clusters - supp_lcn + 1) * vol->cluster_size; - freed_mb = freed_b / NTFS_MBYTE; - - /* WARNING: don't modify the text, external tools grep for it */ - printf("You might resize at %lld bytes ", (long long)new_b); - if ((new_mb * NTFS_MBYTE) < old_b) - printf("or %lld MB ", (long long)new_mb); - - printf("(freeing "); - if (freed_mb && (old_mb - new_mb)) - printf("%lld MB", (long long)(old_mb - new_mb)); - else - printf("%lld bytes", (long long)freed_b); - printf(").\n"); - - printf("Please make a test run using both the -n and -s options " - "before real resizing!\n"); -} - -static void rl_set(runlist *rl, VCN vcn, LCN lcn, s64 len) -{ - rl->vcn = vcn; - rl->lcn = lcn; - rl->length = len; -} - -static int rl_items(runlist *rl) -{ - int i = 0; - - while (rl[i++].length) - ; - - return i; -} - -static void dump_run(runlist_element *r) -{ - ntfs_log_verbose(" %8lld %8lld (0x%08llx) %lld\n", (long long)r->vcn, - (long long)r->lcn, (long long)r->lcn, - (long long)r->length); -} - -static void dump_runlist(runlist *rl) -{ - while (rl->length) - dump_run(rl++); -} - -/** - * nr_clusters_to_bitmap_byte_size - * - * Take the number of clusters in the volume and calculate the size of $Bitmap. - * The size must be always a multiple of 8 bytes. - */ -static s64 nr_clusters_to_bitmap_byte_size(s64 nr_clusters) -{ - s64 bm_bsize; - - bm_bsize = rounded_up_division(nr_clusters, 8); - bm_bsize = (bm_bsize + 7) & ~7; - - return bm_bsize; -} - -static void collect_resize_constraints(ntfs_resize_t *resize, runlist *rl) -{ - s64 inode, last_lcn; - ATTR_FLAGS flags; - ATTR_TYPES atype; - struct llcn_t *llcn = NULL; - int ret, supported = 0; - - last_lcn = rl->lcn + (rl->length - 1); - - inode = resize->ni->mft_no; - flags = resize->ctx->attr->flags; - atype = resize->ctx->attr->type; - - if ((ret = ntfs_inode_badclus_bad(inode, resize->ctx->attr)) != 0) { - if (ret == -1) - perr_exit("Bad sector list check failed"); - return; - } - - if (inode == FILE_Bitmap) { - llcn = &resize->last_lcn; - if (atype == AT_DATA && NInoAttrList(resize->ni)) - err_exit("Highly fragmented $Bitmap isn't supported yet."); - - supported = 1; - - } else if (inode == FILE_MFT) { - llcn = &resize->last_mft; - /* - * First run of $MFT AT_DATA isn't supported yet. - */ - if (atype != AT_DATA || rl->vcn) - supported = 1; - - } else if (NInoAttrList(resize->ni)) { - llcn = &resize->last_multi_mft; - - if (inode != FILE_MFTMirr) - supported = 1; - - } else if (flags & ATTR_IS_SPARSE) { - llcn = &resize->last_sparse; - supported = 1; - - } else if (flags & ATTR_IS_COMPRESSED) { - llcn = &resize->last_compressed; - supported = 1; - - } else if (inode == FILE_MFTMirr) { - llcn = &resize->last_mftmir; - supported = 1; - - /* Fragmented $MFTMirr DATA attribute isn't supported yet */ - if (atype == AT_DATA) - if (rl[1].length != 0 || rl->vcn) - supported = 0; - } else { - llcn = &resize->last_lcn; - supported = 1; - } - - if (llcn->lcn < last_lcn) { - llcn->lcn = last_lcn; - llcn->inode = inode; - } - - if (supported) - return; - - if (resize->last_unsupp < last_lcn) - resize->last_unsupp = last_lcn; -} - - -static void collect_relocation_info(ntfs_resize_t *resize, runlist *rl) -{ - s64 lcn, lcn_length, start, len, inode; - s64 new_vol_size; /* (last LCN on the volume) + 1 */ - - lcn = rl->lcn; - lcn_length = rl->length; - inode = resize->ni->mft_no; - new_vol_size = resize->new_volume_size; - - if (lcn + lcn_length <= new_vol_size) - return; - - if (inode == FILE_Bitmap && resize->ctx->attr->type == AT_DATA) - return; - - start = lcn; - len = lcn_length; - - if (lcn < new_vol_size) { - start = new_vol_size; - len = lcn_length - (new_vol_size - lcn); - - if (!opt.info && (inode == FILE_MFTMirr)) { - err_printf("$MFTMirr can't be split up yet. Please try " - "a different size.\n"); - print_advise(resize->vol, lcn + lcn_length - 1); - exit(1); - } - } - - resize->relocations += len; - - if (!opt.info || !resize->new_volume_size) - return; - - printf("Relocation needed for inode %8lld attr 0x%x LCN 0x%08llx " - "length %6lld\n", (long long)inode, - (unsigned int)le32_to_cpu(resize->ctx->attr->type), - (unsigned long long)start, (long long)len); -} - -/** - * build_lcn_usage_bitmap - * - * lcn_bitmap has one bit for each cluster on the disk. Initially, lcn_bitmap - * has no bits set. As each attribute record is read the bits in lcn_bitmap are - * checked to ensure that no other file already references that cluster. - * - * This serves as a rudimentary "chkdsk" operation. - */ -static void build_lcn_usage_bitmap(ntfs_volume *vol, ntfsck_t *fsck) -{ - s64 inode; - ATTR_RECORD *a; - runlist *rl; - int i, j; - struct bitmap *lcn_bitmap = &fsck->lcn_bitmap; - - a = fsck->ctx->attr; - inode = fsck->ni->mft_no; - - if (!a->non_resident) - return; - - if (!(rl = ntfs_mapping_pairs_decompress(vol, a, NULL))) { - int err = errno; - perr_printf("ntfs_decompress_mapping_pairs"); - if (err == EIO) - printf("%s", corrupt_volume_msg); - exit(1); - } - - - for (i = 0; rl[i].length; i++) { - s64 lcn = rl[i].lcn; - s64 lcn_length = rl[i].length; - - /* CHECKME: LCN_RL_NOT_MAPPED check isn't needed */ - if (lcn == LCN_HOLE || lcn == LCN_RL_NOT_MAPPED) - continue; - - /* FIXME: ntfs_mapping_pairs_decompress should return error */ - if (lcn < 0 || lcn_length <= 0) - err_exit("Corrupt runlist in inode %lld attr %x LCN " - "%llx length %llx\n", inode, - (unsigned int)le32_to_cpu(a->type), lcn, - lcn_length); - - for (j = 0; j < lcn_length; j++) { - u64 k = (u64)lcn + j; - - if (k >= (u64)vol->nr_clusters) { - long long outsiders = lcn_length - j; - - fsck->outsider += outsiders; - - if (++fsck->show_outsider <= 10 || opt.verbose) - printf("Outside of the volume reference" - " for inode %lld at %lld:%lld\n", - inode, (long long)k, outsiders); - - break; - } - - if (ntfs_bit_get_and_set(lcn_bitmap->bm, k, 1)) { - if (++fsck->multi_ref <= 10 || opt.verbose) - printf("Cluster %lld is referenced " - "multiple times!\n", - (long long)k); - continue; - } - } - fsck->inuse += lcn_length; - } - free(rl); -} - - -static ntfs_attr_search_ctx *attr_get_search_ctx(ntfs_inode *ni, MFT_RECORD *mrec) -{ - ntfs_attr_search_ctx *ret; - - if ((ret = ntfs_attr_get_search_ctx(ni, mrec)) == NULL) - perr_printf("ntfs_attr_get_search_ctx"); - - return ret; -} - -/** - * walk_attributes - * - * For a given MFT Record, iterate through all its attributes. Any non-resident - * data runs will be marked in lcn_bitmap. - */ -static int walk_attributes(ntfs_volume *vol, ntfsck_t *fsck) -{ - if (!(fsck->ctx = attr_get_search_ctx(fsck->ni, NULL))) - return -1; - - while (!ntfs_attrs_walk(fsck->ctx)) { - if (fsck->ctx->attr->type == AT_END) - break; - build_lcn_usage_bitmap(vol, fsck); - } - - ntfs_attr_put_search_ctx(fsck->ctx); - return 0; -} - -/** - * compare_bitmaps - * - * Compare two bitmaps. In this case, $Bitmap as read from the disk and - * lcn_bitmap which we built from the MFT Records. - */ -static void compare_bitmaps(ntfs_volume *vol, struct bitmap *a) -{ - s64 i, pos, count; - int mismatch = 0; - int backup_boot = 0; - u8 bm[NTFS_BUF_SIZE]; - - printf("Accounting clusters ...\n"); - - pos = 0; - while (1) { - count = ntfs_attr_pread(vol->lcnbmp_na, pos, NTFS_BUF_SIZE, bm); - if (count == -1) - perr_exit("Couldn't get $Bitmap $DATA"); - - if (count == 0) { - if (a->size > pos) - err_exit("$Bitmap size is smaller than expected" - " (%lld != %lld)\n", a->size, pos); - break; - } - - for (i = 0; i < count; i++, pos++) { - s64 cl; /* current cluster */ - - if (a->size <= pos) - goto done; - - if (a->bm[pos] == bm[i]) - continue; - - for (cl = pos * 8; cl < (pos + 1) * 8; cl++) { - char bit; - - bit = ntfs_bit_get(a->bm, cl); - if (bit == ntfs_bit_get(bm, i * 8 + cl % 8)) - continue; - - if (!mismatch && !bit && !backup_boot && - cl == vol->nr_clusters / 2) { - /* FIXME: call also boot sector check */ - backup_boot = 1; - printf("Found backup boot sector in " - "the middle of the volume.\n"); - continue; - } - - if (++mismatch > 10 && !opt.verbose) - continue; - - printf("Cluster accounting failed at %lld " - "(0x%llx): %s cluster in " - "$Bitmap\n", (long long)cl, - (unsigned long long)cl, - bit ? "missing" : "extra"); - } - } - } -done: - if (mismatch) { - printf("Filesystem check failed! Totally %d cluster " - "accounting mismatches.\n", mismatch); - err_printf("%s", corrupt_volume_msg); - exit(1); - } -} - -/** - * progress_init - * - * Create and scale our progress bar. - */ -static void progress_init(struct progress_bar *p, u64 start, u64 stop, int flags) -{ - p->start = start; - p->stop = stop; - p->unit = 100.0 / (stop - start); - p->resolution = 100; - p->flags = flags; -} - -/** - * progress_update - * - * Update the progress bar and tell the user. - */ -static void progress_update(struct progress_bar *p, u64 current) -{ - float percent; - - if (!(p->flags & NTFS_PROGBAR)) - return; - if (p->flags & NTFS_PROGBAR_SUPPRESS) - return; - - /* WARNING: don't modify the texts, external tools grep for them */ - percent = p->unit * current; - if (current != p->stop) { - if ((current - p->start) % p->resolution) - return; - printf("%6.2f percent completed\r", percent); - } else - printf("100.00 percent completed\n"); - fflush(stdout); -} - -static int inode_close(ntfs_inode *ni) -{ - if (ntfs_inode_close(ni)) { - perr_printf("ntfs_inode_close for inode %llu", - (unsigned long long)ni->mft_no); - return -1; - } - return 0; -} - -/** - * walk_inodes - * - * Read each record in the MFT, skipping the unused ones, and build up a bitmap - * from all the non-resident attributes. - */ -static int build_allocation_bitmap(ntfs_volume *vol, ntfsck_t *fsck) -{ - s64 nr_mft_records, inode = 0; - ntfs_inode *ni; - struct progress_bar progress; - int pb_flags = 0; /* progress bar flags */ - - /* WARNING: don't modify the text, external tools grep for it */ - printf("Checking filesystem consistency ...\n"); - - if (fsck->flags & NTFSCK_PROGBAR) - pb_flags |= NTFS_PROGBAR; - - nr_mft_records = vol->mft_na->initialized_size >> - vol->mft_record_size_bits; - - progress_init(&progress, inode, nr_mft_records - 1, pb_flags); - - for (; inode < nr_mft_records; inode++) { - progress_update(&progress, inode); - - if ((ni = ntfs_inode_open(vol, (MFT_REF)inode)) == NULL) { - /* FIXME: continue only if it make sense, e.g. - MFT record not in use based on $MFT bitmap */ - if (errno == EIO || errno == ENOENT) - continue; - perr_printf("Reading inode %lld failed", inode); - return -1; - } - - if (ni->mrec->base_mft_record) - goto close_inode; - - fsck->ni = ni; - if (walk_attributes(vol, fsck) != 0) { - inode_close(ni); - return -1; - } -close_inode: - if (inode_close(ni) != 0) - return -1; - } - return 0; -} - -static void build_resize_constraints(ntfs_resize_t *resize) -{ - s64 i; - runlist *rl; - - if (!resize->ctx->attr->non_resident) - return; - - if (!(rl = ntfs_mapping_pairs_decompress(resize->vol, - resize->ctx->attr, NULL))) - perr_exit("ntfs_decompress_mapping_pairs"); - - for (i = 0; rl[i].length; i++) { - /* CHECKME: LCN_RL_NOT_MAPPED check isn't needed */ - if (rl[i].lcn == LCN_HOLE || rl[i].lcn == LCN_RL_NOT_MAPPED) - continue; - - collect_resize_constraints(resize, rl + i); - if (resize->shrink) - collect_relocation_info(resize, rl + i); - } - free(rl); -} - -static void resize_constraints_by_attributes(ntfs_resize_t *resize) -{ - if (!(resize->ctx = attr_get_search_ctx(resize->ni, NULL))) - exit(1); - - while (!ntfs_attrs_walk(resize->ctx)) { - if (resize->ctx->attr->type == AT_END) - break; - build_resize_constraints(resize); - } - - ntfs_attr_put_search_ctx(resize->ctx); -} - -static void set_resize_constraints(ntfs_resize_t *resize) -{ - s64 nr_mft_records, inode; - ntfs_inode *ni; - - printf("Collecting resizing constraints ...\n"); - - nr_mft_records = resize->vol->mft_na->initialized_size >> - resize->vol->mft_record_size_bits; - - for (inode = 0; inode < nr_mft_records; inode++) { - - ni = ntfs_inode_open(resize->vol, (MFT_REF)inode); - if (ni == NULL) { - if (errno == EIO || errno == ENOENT) - continue; - perr_exit("Reading inode %lld failed", inode); - } - - if (ni->mrec->base_mft_record) - goto close_inode; - - resize->ni = ni; - resize_constraints_by_attributes(resize); -close_inode: - if (inode_close(ni) != 0) - exit(1); - } -} - -static void rl_fixup(runlist **rl) -{ - runlist *tmp = *rl; - - if (tmp->lcn == LCN_RL_NOT_MAPPED) { - s64 unmapped_len = tmp->length; - - ntfs_log_verbose("Skip unmapped run at the beginning ...\n"); - - if (!tmp->length) - err_exit("Empty unmapped runlist! Please report!\n"); - (*rl)++; - for (tmp = *rl; tmp->length; tmp++) - tmp->vcn -= unmapped_len; - } - - for (tmp = *rl; tmp->length; tmp++) { - if (tmp->lcn == LCN_RL_NOT_MAPPED) { - ntfs_log_verbose("Skip unmapped run at the end ...\n"); - - if (tmp[1].length) - err_exit("Unmapped runlist in the middle! " - "Please report!\n"); - tmp->lcn = LCN_ENOENT; - tmp->length = 0; - } - } -} - -static void replace_attribute_runlist(ntfs_volume *vol, - ntfs_attr_search_ctx *ctx, - runlist *rl) -{ - int mp_size, l; - void *mp; - ATTR_RECORD *a = ctx->attr; - - rl_fixup(&rl); - - if ((mp_size = ntfs_get_size_for_mapping_pairs(vol, rl, 0)) == -1) - perr_exit("ntfs_get_size_for_mapping_pairs"); - - if (a->name_length) { - u16 name_offs = le16_to_cpu(a->name_offset); - u16 mp_offs = le16_to_cpu(a->u.nonres.mapping_pairs_offset); - - if (name_offs >= mp_offs) - err_exit("Attribute name is after mapping pairs! " - "Please report!\n"); - } - - /* CHECKME: don't trust mapping_pairs is always the last item in the - attribute, instead check for the real size/space */ - l = (int)le32_to_cpu(a->length) - le16_to_cpu(a->u.nonres.mapping_pairs_offset); - if (mp_size > l) { - s64 remains_size; - char *next_attr; - - ntfs_log_verbose("Enlarging attribute header ...\n"); - - mp_size = (mp_size + 7) & ~7; - - ntfs_log_verbose("Old mp size : %d\n", l); - ntfs_log_verbose("New mp size : %d\n", mp_size); - ntfs_log_verbose("Bytes in use : %u\n", (unsigned int) - le32_to_cpu(ctx->mrec->bytes_in_use)); - - next_attr = (char *)a + le32_to_cpu(a->length); - l = mp_size - l; - - ntfs_log_verbose("Bytes in use new : %u\n", l + (unsigned int) - le32_to_cpu(ctx->mrec->bytes_in_use)); - ntfs_log_verbose("Bytes allocated : %u\n", (unsigned int) - le32_to_cpu(ctx->mrec->bytes_allocated)); - - remains_size = le32_to_cpu(ctx->mrec->bytes_in_use); - remains_size -= (next_attr - (char *)ctx->mrec); - - ntfs_log_verbose("increase : %d\n", l); - ntfs_log_verbose("shift : %lld\n", - (long long)remains_size); - - if (le32_to_cpu(ctx->mrec->bytes_in_use) + l > - le32_to_cpu(ctx->mrec->bytes_allocated)) - err_exit("Extended record needed (%u > %u), not yet " - "supported!\nPlease try to free less space.\n", - (unsigned int)le32_to_cpu(ctx->mrec-> - bytes_in_use) + l, - (unsigned int)le32_to_cpu(ctx->mrec-> - bytes_allocated)); - - memmove(next_attr + l, next_attr, remains_size); - ctx->mrec->bytes_in_use = cpu_to_le32(l + - le32_to_cpu(ctx->mrec->bytes_in_use)); - a->length = cpu_to_le32(le32_to_cpu(a->length) + l); - } - - mp = ntfs_calloc(mp_size); - if (!mp) - perr_exit("ntfsc_calloc couldn't get memory"); - - if (ntfs_mapping_pairs_build(vol, mp, mp_size, rl, 0, NULL)) - perr_exit("ntfs_mapping_pairs_build"); - - memmove((u8*)a + le16_to_cpu(a->u.nonres.mapping_pairs_offset), mp, mp_size); - - free(mp); -} - -static void set_bitmap_range(struct bitmap *bm, s64 pos, s64 length, u8 bit) -{ - while (length--) - ntfs_bit_set(bm->bm, pos++, bit); -} - -static void set_bitmap_clusters(struct bitmap *bm, runlist *rl, u8 bit) -{ - for (; rl->length; rl++) - set_bitmap_range(bm, rl->lcn, rl->length, bit); -} - -static void release_bitmap_clusters(struct bitmap *bm, runlist *rl) -{ - max_free_cluster_range = 0; - set_bitmap_clusters(bm, rl, 0); -} - -static void set_max_free_zone(s64 length, s64 end, runlist_element *rle) -{ - if (length > rle->length) { - rle->lcn = end - length; - rle->length = length; - } -} - -static int find_free_cluster(struct bitmap *bm, - runlist_element *rle, - s64 nr_vol_clusters, - int hint) -{ - /* FIXME: get rid of this 'static' variable */ - static s64 pos = 0; - s64 i, items = rle->length; - s64 free_zone = 0; - - if (pos >= nr_vol_clusters) - pos = 0; - if (!max_free_cluster_range) - max_free_cluster_range = nr_vol_clusters; - rle->lcn = rle->length = 0; - if (hint) - pos = nr_vol_clusters / 2; - i = pos; - - do { - if (!ntfs_bit_get(bm->bm, i)) { - if (++free_zone == items) { - set_max_free_zone(free_zone, i + 1, rle); - break; - } - } else { - set_max_free_zone(free_zone, i, rle); - free_zone = 0; - } - if (++i == nr_vol_clusters) { - set_max_free_zone(free_zone, i, rle); - i = free_zone = 0; - } - if (rle->length == max_free_cluster_range) - break; - } while (i != pos); - - if (i) - set_max_free_zone(free_zone, i, rle); - - if (!rle->lcn) { - errno = ENOSPC; - return -1; - } - if (rle->length < items && rle->length < max_free_cluster_range) { - max_free_cluster_range = rle->length; - ntfs_log_verbose("Max free range: %7lld \n", - (long long)max_free_cluster_range); - } - pos = rle->lcn + items; - if (pos == nr_vol_clusters) - pos = 0; - - set_bitmap_range(bm, rle->lcn, rle->length, 1); - return 0; -} - -static runlist *alloc_cluster(struct bitmap *bm, - s64 items, - s64 nr_vol_clusters, - int hint) -{ - runlist_element rle; - runlist *rl = NULL; - int rl_size, runs = 0; - s64 vcn = 0; - - if (items <= 0) { - errno = EINVAL; - return NULL; - } - - while (items > 0) { - - if (runs) - hint = 0; - rle.length = items; - if (find_free_cluster(bm, &rle, nr_vol_clusters, hint) == -1) - return NULL; - - rl_size = (runs + 2) * sizeof(runlist_element); - if (!(rl = (runlist *)realloc(rl, rl_size))) - return NULL; - - rl_set(rl + runs, vcn, rle.lcn, rle.length); - - vcn += rle.length; - items -= rle.length; - runs++; - } - - rl_set(rl + runs, vcn, -1LL, 0LL); - - if (runs > 1) { - ntfs_log_verbose("Multi-run allocation: \n"); - dump_runlist(rl); - } - return rl; -} - -static int read_all(struct ntfs_device *dev, void *buf, int count) -{ - int i; - - while (count > 0) { - - i = count; - if (!NDevReadOnly(dev)) - i = dev->d_ops->read(dev, buf, count); - - if (i < 0) { - if (errno != EAGAIN && errno != EINTR) - return -1; - } else if (i > 0) { - count -= i; - buf = i + (char *)buf; - } else - err_exit("Unexpected end of file!\n"); - } - return 0; -} - -static int write_all(struct ntfs_device *dev, void *buf, int count) -{ - int i; - - while (count > 0) { - - i = count; - if (!NDevReadOnly(dev)) - i = dev->d_ops->write(dev, buf, count); - - if (i < 0) { - if (errno != EAGAIN && errno != EINTR) - return -1; - } else { - count -= i; - buf = i + (char *)buf; - } - } - return 0; -} - -/** - * write_mft_record - * - * Write an MFT Record back to the disk. If the read-only command line option - * was given, this function will do nothing. - */ -static int write_mft_record(ntfs_volume *v, const MFT_REF mref, MFT_RECORD *buf) -{ - if (ntfs_mft_record_write(v, mref, buf)) - perr_exit("ntfs_mft_record_write"); - -// if (v->u.dev->d_ops->sync(v->u.dev) == -1) -// perr_exit("Failed to sync device"); - - return 0; -} - -static void lseek_to_cluster(ntfs_volume *vol, s64 lcn) -{ - off_t pos; - pos = (off_t)(lcn * vol->cluster_size); - if (vol->u.dev->d_ops->seek(vol->u.dev, pos, SEEK_SET) == (off_t)-1) - perr_exit("seek failed to position %lld", lcn); -} - -static void copy_clusters(ntfs_resize_t *resize, s64 dest, s64 src, s64 len) -{ - s64 i; - char buff[NTFS_MAX_CLUSTER_SIZE]; /* overflow checked at mount time */ - ntfs_volume *vol = resize->vol; - - for (i = 0; i < len; i++) { - - lseek_to_cluster(vol, src + i); - - if (read_all(vol->u.dev, buff, vol->cluster_size) == -1) { - perr_printf("Failed to read from the disk"); - if (errno == EIO) - printf("%s", bad_sectors_warning_msg); - exit(1); - } - - lseek_to_cluster(vol, dest + i); - - if (write_all(vol->u.dev, buff, vol->cluster_size) == -1) { - perr_printf("Failed to write to the disk"); - if (errno == EIO) - printf("%s", bad_sectors_warning_msg); - exit(1); - } - - resize->relocations++; - progress_update(&resize->progress, resize->relocations); - } -} - -static void relocate_clusters(ntfs_resize_t *r, runlist *dest_rl, s64 src_lcn) -{ - /* collect_shrink_constraints() ensured $MFTMir DATA is one run */ - if (r->mref == FILE_MFTMirr && r->ctx->attr->type == AT_DATA) { - if (!r->mftmir_old) { - r->mftmir_rl.lcn = dest_rl->lcn; - r->mftmir_rl.length = dest_rl->length; - r->mftmir_old = src_lcn; - } else - err_exit("Multi-run $MFTMirr. Please report!\n"); - } - - for (; dest_rl->length; src_lcn += dest_rl->length, dest_rl++) - copy_clusters(r, dest_rl->lcn, src_lcn, dest_rl->length); -} - -static void rl_split_run(runlist **rl, int run, s64 pos) -{ - runlist *rl_new, *rle_new, *rle; - int items, new_size, size_head, size_tail; - s64 len_head, len_tail; - - items = rl_items(*rl); - new_size = (items + 1) * sizeof(runlist_element); - size_head = run * sizeof(runlist_element); - size_tail = (items - run - 1) * sizeof(runlist_element); - - rl_new = ntfs_malloc(new_size); - if (!rl_new) - perr_exit("ntfs_malloc"); - - rle_new = rl_new + run; - rle = *rl + run; - - memmove(rl_new, *rl, size_head); - memmove(rle_new + 2, rle + 1, size_tail); - - len_tail = rle->length - (pos - rle->lcn); - len_head = rle->length - len_tail; - - rl_set(rle_new, rle->vcn, rle->lcn, len_head); - rl_set(rle_new + 1, rle->vcn + len_head, rle->lcn + len_head, len_tail); - - ntfs_log_verbose("Splitting run at cluster %lld:\n", (long long)pos); - dump_run(rle); dump_run(rle_new); dump_run(rle_new + 1); - - free(*rl); - *rl = rl_new; -} - -static void rl_insert_at_run(runlist **rl, int run, runlist *ins) -{ - int items, ins_items; - int new_size, size_tail; - runlist *rle; - s64 vcn; - - items = rl_items(*rl); - ins_items = rl_items(ins) - 1; - new_size = ((items - 1) + ins_items) * sizeof(runlist_element); - size_tail = (items - run - 1) * sizeof(runlist_element); - - if (!(*rl = (runlist *)realloc(*rl, new_size))) - perr_exit("realloc"); - - rle = *rl + run; - - memmove(rle + ins_items, rle + 1, size_tail); - - for (vcn = rle->vcn; ins->length; rle++, vcn += ins->length, ins++) { - rl_set(rle, vcn, ins->lcn, ins->length); -// dump_run(rle); - } - - return; - - /* FIXME: fast path if ins_items = 1 */ -// (*rl + run)->lcn = ins->lcn; -} - -static void relocate_run(ntfs_resize_t *resize, runlist **rl, int run) -{ - s64 lcn, lcn_length; - s64 new_vol_size; /* (last LCN on the volume) + 1 */ - runlist *relocate_rl; /* relocate runlist to relocate_rl */ - int hint; - - lcn = (*rl + run)->lcn; - lcn_length = (*rl + run)->length; - new_vol_size = resize->new_volume_size; - - if (lcn + lcn_length <= new_vol_size) - return; - - if (lcn < new_vol_size) { - rl_split_run(rl, run, new_vol_size); - return; - } - - hint = (resize->mref == FILE_MFTMirr) ? 1 : 0; - if (!(relocate_rl = alloc_cluster(&resize->lcn_bitmap, lcn_length, - new_vol_size, hint))) - perr_exit("Cluster allocation failed for %llu:%lld", - resize->mref, lcn_length); - - /* FIXME: check $MFTMirr DATA isn't multi-run (or support it) */ - ntfs_log_verbose("Relocate record %7llu:0x%x:%08lld:0x%08llx:0x%08llx " - "--> 0x%08llx\n", (unsigned long long)resize->mref, - (unsigned int)le32_to_cpu(resize->ctx->attr->type), - (long long)lcn_length, - (unsigned long long)(*rl + run)->vcn, - (unsigned long long)lcn, - (unsigned long long)relocate_rl->lcn); - - relocate_clusters(resize, relocate_rl, lcn); - rl_insert_at_run(rl, run, relocate_rl); - - /* We don't release old clusters in the bitmap, that area isn't - used by the allocator and will be truncated later on */ - free(relocate_rl); - - resize->dirty_inode = DIRTY_ATTRIB; -} - -static void relocate_attribute(ntfs_resize_t *resize) -{ - ATTR_RECORD *a; - runlist *rl; - int i; - - a = resize->ctx->attr; - - if (!a->non_resident) - return; - - if (!(rl = ntfs_mapping_pairs_decompress(resize->vol, a, NULL))) - perr_exit("ntfs_decompress_mapping_pairs"); - - for (i = 0; rl[i].length; i++) { - s64 lcn = rl[i].lcn; - s64 lcn_length = rl[i].length; - - if (lcn == LCN_HOLE || lcn == LCN_RL_NOT_MAPPED) - continue; - - /* FIXME: ntfs_mapping_pairs_decompress should return error */ - if (lcn < 0 || lcn_length <= 0) - err_exit("Corrupt runlist in MTF %llu attr %x LCN " - "%llx length %llx\n", resize->mref, - (unsigned int)le32_to_cpu(a->type), - lcn, lcn_length); - - relocate_run(resize, &rl, i); - } - - if (resize->dirty_inode == DIRTY_ATTRIB) { - replace_attribute_runlist(resize->vol, resize->ctx, rl); - resize->dirty_inode = DIRTY_INODE; - } - - free(rl); -} - -static int is_mftdata(ntfs_resize_t *resize) -{ - if (resize->ctx->attr->type != AT_DATA) - return 0; - - if (resize->mref == 0) - return 1; - - if (MREF_LE(resize->mrec->base_mft_record) == 0 && - MSEQNO_LE(resize->mrec->base_mft_record) != 0) - return 1; - - return 0; -} - -static int handle_mftdata(ntfs_resize_t *resize, int do_mftdata) -{ - ATTR_RECORD *attr = resize->ctx->attr; - VCN highest_vcn, lowest_vcn; - - if (do_mftdata) { - - if (!is_mftdata(resize)) - return 0; - - highest_vcn = sle64_to_cpu(attr->u.nonres.highest_vcn); - lowest_vcn = sle64_to_cpu(attr->u.nonres.lowest_vcn); - - if (resize->mft_highest_vcn != highest_vcn) - return 0; - - if (lowest_vcn == 0) - resize->mft_highest_vcn = lowest_vcn; - else - resize->mft_highest_vcn = lowest_vcn - 1; - - } else if (is_mftdata(resize)) { - - highest_vcn = sle64_to_cpu(attr->u.nonres.highest_vcn); - - if (resize->mft_highest_vcn < highest_vcn) - resize->mft_highest_vcn = highest_vcn; - - return 0; - } - - return 1; -} - -static void relocate_attributes(ntfs_resize_t *resize, int do_mftdata) -{ - int ret; - - if (!(resize->ctx = attr_get_search_ctx(NULL, resize->mrec))) - exit(1); - - while (!ntfs_attrs_walk(resize->ctx)) { - if (resize->ctx->attr->type == AT_END) - break; - - if (handle_mftdata(resize, do_mftdata) == 0) - continue; - - ret = ntfs_inode_badclus_bad(resize->mref, resize->ctx->attr); - if (ret == -1) - perr_exit("Bad sector list check failed"); - else if (ret == 1) - continue; - - if (resize->mref == FILE_Bitmap && - resize->ctx->attr->type == AT_DATA) - continue; - - relocate_attribute(resize); - } - - ntfs_attr_put_search_ctx(resize->ctx); -} - -static void relocate_inode(ntfs_resize_t *resize, MFT_REF mref, int do_mftdata) -{ - if (ntfs_file_record_read(resize->vol, mref, &resize->mrec, NULL)) { - /* FIXME: continue only if it make sense, e.g. - MFT record not in use based on $MFT bitmap */ - if (errno == EIO || errno == ENOENT) - return; - perr_exit("ntfs_file_record_record"); - } - - if (!(resize->mrec->flags & MFT_RECORD_IN_USE)) - return; - - resize->mref = mref; - resize->dirty_inode = DIRTY_NONE; - - relocate_attributes(resize, do_mftdata); - - if (resize->dirty_inode == DIRTY_INODE) { -// if (vol->u.dev->d_ops->sync(vol->u.dev) == -1) -// perr_exit("Failed to sync device"); - if (write_mft_record(resize->vol, mref, resize->mrec)) - perr_exit("Couldn't update record %llu", mref); - } -} - -static void relocate_inodes(ntfs_resize_t *resize) -{ - s64 nr_mft_records; - MFT_REF mref; - VCN highest_vcn; - - printf("Relocating needed data ...\n"); - - progress_init(&resize->progress, 0, resize->relocations, resize->progress.flags); - resize->relocations = 0; - - resize->mrec = ntfs_malloc(resize->vol->mft_record_size); - if (!resize->mrec) - perr_exit("ntfs_malloc failed"); - - nr_mft_records = resize->vol->mft_na->initialized_size >> - resize->vol->mft_record_size_bits; - - for (mref = 0; mref < (MFT_REF)nr_mft_records; mref++) - relocate_inode(resize, mref, 0); - - while (1) { - highest_vcn = resize->mft_highest_vcn; - mref = nr_mft_records; - do { - relocate_inode(resize, --mref, 1); - if (resize->mft_highest_vcn == 0) - goto done; - } while (mref); - - if (highest_vcn == resize->mft_highest_vcn) - err_exit("Sanity check failed! Highest_vcn = %lld. " - "Please report!\n", highest_vcn); - } -done: - free(resize->mrec); -} - -static void print_hint(ntfs_volume *vol, const char *s, struct llcn_t llcn) -{ - s64 runs_b, runs_mb; - - if (llcn.lcn == 0) - return; - - runs_b = llcn.lcn * vol->cluster_size; - runs_mb = rounded_up_division(runs_b, NTFS_MBYTE); - printf("%-19s: %9lld MB %8lld\n", s, (long long)runs_mb, - (long long)llcn.inode); -} - -/** - * advise_on_resize - * - * The metadata file $Bitmap has one bit for each cluster on disk. This has - * already been read into lcn_bitmap. By looking for the last used cluster on - * the disk, we can work out by how much we can shrink the volume. - */ -static void advise_on_resize(ntfs_resize_t *resize) -{ - ntfs_volume *vol = resize->vol; - - if (opt.verbose) { - printf("Estimating smallest shrunken size supported ...\n"); - printf("File feature Last used at By inode\n"); - print_hint(vol, "$MFT", resize->last_mft); - print_hint(vol, "Multi-Record", resize->last_multi_mft); - print_hint(vol, "$MFTMirr", resize->last_mftmir); - print_hint(vol, "Compressed", resize->last_compressed); - print_hint(vol, "Sparse", resize->last_sparse); - print_hint(vol, "Ordinary", resize->last_lcn); - } - - print_advise(vol, resize->last_unsupp); -} - - -static void rl_expand(runlist **rl, const VCN last_vcn) -{ - int len; - runlist *p = *rl; - - len = rl_items(p) - 1; - if (len <= 0) - err_exit("rl_expand: bad runlist length: %d\n", len); - - if (p[len].vcn > last_vcn) - err_exit("rl_expand: length is already more than requested " - "(%lld > %lld)\n", p[len].vcn, last_vcn); - - if (p[len - 1].lcn == LCN_HOLE) { - - p[len - 1].length += last_vcn - p[len].vcn; - p[len].vcn = last_vcn; - - } else if (p[len - 1].lcn >= 0) { - - p = realloc(*rl, (++len + 1) * sizeof(runlist_element)); - if (!p) - perr_exit("rl_expand: realloc"); - - p[len - 1].lcn = LCN_HOLE; - p[len - 1].length = last_vcn - p[len - 1].vcn; - rl_set(p + len, last_vcn, LCN_ENOENT, 0LL); - *rl = p; - - } else - err_exit("rl_expand: bad LCN: %lld\n", p[len - 1].lcn); -} - -static void rl_truncate(runlist **rl, const VCN last_vcn) -{ - int len; - VCN vcn; - - len = rl_items(*rl) - 1; - if (len <= 0) - err_exit("rl_truncate: bad runlist length: %d\n", len); - - vcn = (*rl)[len].vcn; - - if (vcn < last_vcn) - rl_expand(rl, last_vcn); - - else if (vcn > last_vcn) - if (ntfs_rl_truncate(rl, last_vcn) == -1) - perr_exit("ntfs_rl_truncate"); -} - -/** - * bitmap_file_data_fixup - * - * $Bitmap can overlap the end of the volume. Any bits in this region - * must be set. This region also encompasses the backup boot sector. - */ -static void bitmap_file_data_fixup(s64 cluster, struct bitmap *bm) -{ - for (; cluster < bm->size << 3; cluster++) - ntfs_bit_set(bm->bm, (u64)cluster, 1); -} - -/** - * truncate_badclust_bad_attr - * - * The metadata file $BadClus needs to be shrunk. - * - * FIXME: this function should go away and instead using a generalized - * "truncate_bitmap_data_attr()" - */ -static void truncate_badclust_bad_attr(ntfs_resize_t *resize) -{ - ATTR_RECORD *a; - runlist *rl_bad; - s64 nr_clusters = resize->new_volume_size; - ntfs_volume *vol = resize->vol; - - a = resize->ctx->attr; - if (!a->non_resident) - /* FIXME: handle resident attribute value */ - err_exit("Resident attribute in $BadClust isn't supported!\n"); - - if (!(rl_bad = ntfs_mapping_pairs_decompress(vol, a, NULL))) - perr_exit("ntfs_mapping_pairs_decompress"); - - rl_truncate(&rl_bad, nr_clusters); - - a->u.nonres.highest_vcn = cpu_to_sle64(nr_clusters - 1LL); - a->u.nonres.allocated_size = cpu_to_sle64(nr_clusters * vol->cluster_size); - a->u.nonres.data_size = cpu_to_sle64(nr_clusters * vol->cluster_size); - - replace_attribute_runlist(vol, resize->ctx, rl_bad); - - free(rl_bad); -} - -/** - * realloc_bitmap_data_attr - * - * Reallocate the metadata file $Bitmap. It must be large enough for one bit - * per cluster of the shrunken volume. Also it must be a of 8 bytes in size. - */ -static void realloc_bitmap_data_attr(ntfs_resize_t *resize, - runlist **rl, - s64 nr_bm_clusters) -{ - s64 i; - ntfs_volume *vol = resize->vol; - ATTR_RECORD *a = resize->ctx->attr; - s64 new_size = resize->new_volume_size; - struct bitmap *bm = &resize->lcn_bitmap; - - if (!(*rl = ntfs_mapping_pairs_decompress(vol, a, NULL))) - perr_exit("ntfs_mapping_pairs_decompress"); - - release_bitmap_clusters(bm, *rl); - free(*rl); - - for (i = vol->nr_clusters; i < new_size; i++) - ntfs_bit_set(bm->bm, i, 0); - - if (!(*rl = alloc_cluster(bm, nr_bm_clusters, new_size, 0))) - perr_exit("Couldn't allocate $Bitmap clusters"); -} - -static void realloc_lcn_bitmap(ntfs_resize_t *resize, s64 bm_bsize) -{ - u8 *tmp; - - if (!(tmp = realloc(resize->lcn_bitmap.bm, bm_bsize))) - perr_exit("realloc"); - - resize->lcn_bitmap.bm = tmp; - resize->lcn_bitmap.size = bm_bsize; - bitmap_file_data_fixup(resize->new_volume_size, &resize->lcn_bitmap); -} - -/** - * truncate_bitmap_data_attr - */ -static void truncate_bitmap_data_attr(ntfs_resize_t *resize) -{ - ATTR_RECORD *a; - runlist *rl; - s64 bm_bsize, size; - s64 nr_bm_clusters; - ntfs_volume *vol = resize->vol; - - a = resize->ctx->attr; - if (!a->non_resident) - /* FIXME: handle resident attribute value */ - err_exit("Resident attribute in $Bitmap isn't supported!\n"); - - bm_bsize = nr_clusters_to_bitmap_byte_size(resize->new_volume_size); - nr_bm_clusters = rounded_up_division(bm_bsize, vol->cluster_size); - - if (resize->shrink) { - realloc_bitmap_data_attr(resize, &rl, nr_bm_clusters); - realloc_lcn_bitmap(resize, bm_bsize); - } else { - realloc_lcn_bitmap(resize, bm_bsize); - realloc_bitmap_data_attr(resize, &rl, nr_bm_clusters); - } - - a->u.nonres.highest_vcn = cpu_to_sle64(nr_bm_clusters - 1LL); - a->u.nonres.allocated_size = cpu_to_sle64(nr_bm_clusters * vol->cluster_size); - a->u.nonres.data_size = cpu_to_sle64(bm_bsize); - a->u.nonres.initialized_size = cpu_to_sle64(bm_bsize); - - replace_attribute_runlist(vol, resize->ctx, rl); - - /* - * FIXME: update allocated/data sizes and timestamps in $FILE_NAME - * attribute too, for now chkdsk will do this for us. - */ - - size = ntfs_rl_pwrite(vol, rl, 0, bm_bsize, resize->lcn_bitmap.bm); - if (bm_bsize != size) { - if (size == -1) - perr_exit("Couldn't write $Bitmap"); - err_exit("Couldn't write full $Bitmap file (%lld from %lld)\n", - (long long)size, (long long)bm_bsize); - } - - free(rl); -} - -/** - * lookup_data_attr - * - * Find the $DATA attribute (with or without a name) for the given MFT reference - * (inode number). - */ -static void lookup_data_attr(ntfs_volume *vol, - MFT_REF mref, - const char *aname, - ntfs_attr_search_ctx **ctx) -{ - ntfs_inode *ni; - ntfschar *ustr; - int len = 0; - - if (!(ni = ntfs_inode_open(vol, mref))) - perr_exit("ntfs_open_inode"); - - if (!(*ctx = attr_get_search_ctx(ni, NULL))) - exit(1); - - if ((ustr = ntfs_str2ucs(aname, &len)) == NULL) { - perr_printf("Couldn't convert '%s' to Unicode", aname); - exit(1); - } - - if (ntfs_attr_lookup(AT_DATA, ustr, len, 0, 0, NULL, 0, *ctx)) - perr_exit("ntfs_lookup_attr"); - - ntfs_ucsfree(ustr); -} - -static int check_bad_sectors(ntfs_volume *vol) -{ - ntfs_attr_search_ctx *ctx; - ntfs_inode *base_ni; - runlist *rl; - s64 i, badclusters = 0; - - ntfs_log_verbose("Checking for bad sectors ...\n"); - - lookup_data_attr(vol, FILE_BadClus, "$Bad", &ctx); - - base_ni = ctx->base_ntfs_ino; - if (!base_ni) - base_ni = ctx->ntfs_ino; - - if (NInoAttrList(base_ni)) { - err_printf("Hopelessly many bad sectors has been detected!\n"); - printf("%s", many_bad_sectors_msg); - exit(1); - } - - if (!ctx->attr->non_resident) - err_exit("Resident attribute in $BadClust! Please report to " - "%s\n", NTFS_DEV_LIST); - /* - * FIXME: The below would be partial for non-base records in the - * not yet supported multi-record case. Alternatively use audited - * ntfs_attr_truncate after an umount & mount. - */ - if (!(rl = ntfs_mapping_pairs_decompress(vol, ctx->attr, NULL))) - perr_exit("Decompressing $BadClust:$Bad mapping pairs failed"); - - for (i = 0; rl[i].length; i++) { - /* CHECKME: LCN_RL_NOT_MAPPED check isn't needed */ - if (rl[i].lcn == LCN_HOLE || rl[i].lcn == LCN_RL_NOT_MAPPED) - continue; - - badclusters += rl[i].length; - ntfs_log_verbose("Bad cluster: %#8llx - %#llx (%lld)\n", - rl[i].lcn, rl[i].lcn + rl[i].length - 1, - rl[i].length); - } - - if (badclusters) { - printf("%sThis software has detected that the disk has at least" - " %lld bad sector%s.\n", - !opt.badsectors ? NERR_PREFIX : "WARNING: ", - badclusters, badclusters - 1 ? "s" : ""); - if (!opt.badsectors) { - printf("%s", bad_sectors_warning_msg); - exit(1); - } else - printf("WARNING: Bad sectors can cause reliability " - "problems and massive data loss!!!\n"); - } - - free(rl); - ntfs_attr_put_search_ctx(ctx); - - return badclusters; -} - -/** - * truncate_badclust_file - * - * Shrink the $BadClus file to match the new volume size. - */ -static void truncate_badclust_file(ntfs_resize_t *resize) -{ - printf("Updating $BadClust file ...\n"); - - lookup_data_attr(resize->vol, FILE_BadClus, "$Bad", &resize->ctx); - /* FIXME: sanity_check_attr(ctx->attr); */ - truncate_badclust_bad_attr(resize); - - if (write_mft_record(resize->vol, resize->ctx->ntfs_ino->mft_no, - resize->ctx->mrec)) - perr_exit("Couldn't update $BadClust"); - - ntfs_attr_put_search_ctx(resize->ctx); -} - -/** - * truncate_bitmap_file - * - * Shrink the $Bitmap file to match the new volume size. - */ -static void truncate_bitmap_file(ntfs_resize_t *resize) -{ - printf("Updating $Bitmap file ...\n"); - - lookup_data_attr(resize->vol, FILE_Bitmap, NULL, &resize->ctx); - truncate_bitmap_data_attr(resize); - - if (write_mft_record(resize->vol, resize->ctx->ntfs_ino->mft_no, - resize->ctx->mrec)) - perr_exit("Couldn't update $Bitmap"); - - ntfs_attr_put_search_ctx(resize->ctx); -} - -/** - * setup_lcn_bitmap - * - * Allocate a block of memory with one bit for each cluster of the disk. - * All the bits are set to 0, except those representing the region beyond the - * end of the disk. - */ -static int setup_lcn_bitmap(struct bitmap *bm, s64 nr_clusters) -{ - /* Determine lcn bitmap byte size and allocate it. */ - bm->size = rounded_up_division(nr_clusters, 8); - - bm->bm = ntfs_calloc(bm->size); - if (!bm->bm) - return -1; - - bitmap_file_data_fixup(nr_clusters, bm); - return 0; -} - -/** - * update_bootsector - * - * FIXME: should be done using ntfs_* functions - */ -static void update_bootsector(ntfs_resize_t *r) -{ - NTFS_BOOT_SECTOR bs; - s64 bs_size = sizeof(NTFS_BOOT_SECTOR); - ntfs_volume *vol = r->vol; - - printf("Updating Boot record ...\n"); - - if (vol->u.dev->d_ops->seek(vol->u.dev, 0, SEEK_SET) == (off_t)-1) - perr_exit("lseek"); - - if (vol->u.dev->d_ops->read(vol->u.dev, &bs, bs_size) == -1) - perr_exit("read() error"); - - bs.number_of_sectors = cpu_to_sle64(r->new_volume_size * - bs.bpb.sectors_per_cluster); - - if (r->mftmir_old) { - r->progress.flags |= NTFS_PROGBAR_SUPPRESS; - copy_clusters(r, r->mftmir_rl.lcn, r->mftmir_old, - r->mftmir_rl.length); - bs.mftmirr_lcn = cpu_to_sle64(r->mftmir_rl.lcn); - r->progress.flags &= ~NTFS_PROGBAR_SUPPRESS; - } - - if (vol->u.dev->d_ops->seek(vol->u.dev, 0, SEEK_SET) == (off_t)-1) - perr_exit("lseek"); - - if (!opt.ro_flag) - if (vol->u.dev->d_ops->write(vol->u.dev, &bs, bs_size) == -1) - perr_exit("write() error"); -} - -/** - * vol_size - */ -static s64 vol_size(ntfs_volume *v, s64 nr_clusters) -{ - /* add one sector_size for the backup boot sector */ - return nr_clusters * v->cluster_size + v->sector_size; -} - -/** - * print_vol_size - * - * Print the volume size in bytes and decimal megabytes. - */ -static void print_vol_size(const char *str, s64 bytes) -{ - printf("%s: %lld bytes (%lld MB)\n", str, (long long)bytes, - (long long)rounded_up_division(bytes, NTFS_MBYTE)); -} - -/** - * print_disk_usage - * - * Display the amount of disk space in use. - */ -static void print_disk_usage(ntfs_volume *vol, s64 nr_used_clusters) -{ - s64 total, used; - - total = vol->nr_clusters * vol->cluster_size; - used = nr_used_clusters * vol->cluster_size; - - /* WARNING: don't modify the text, external tools grep for it */ - printf("Space in use : %lld MB (%.1f%%)\n", - (long long)rounded_up_division(used, NTFS_MBYTE), - 100.0 * ((float)used / total)); -} - -static void print_num_of_relocations(ntfs_resize_t *resize) -{ - s64 relocations = resize->relocations * resize->vol->cluster_size; - - printf("Needed relocations : %lld (%lld MB)\n", - (long long)resize->relocations, (long long) - rounded_up_division(relocations, NTFS_MBYTE)); -} - -/** - * mount_volume - * - * First perform some checks to determine if the volume is already mounted, or - * is dirty (Windows wasn't shutdown properly). If everything is OK, then mount - * the volume (load the metadata into memory). - */ -static ntfs_volume *mount_volume(void) -{ - unsigned long mntflag; - ntfs_volume *vol = NULL; - - if (ntfs_check_if_mounted(opt.volume, &mntflag)) { - perr_printf("Failed to check '%s' mount state", opt.volume); - printf("Probably /etc/mtab is missing. It's too risky to " - "continue. You might try\nan another Linux distro.\n"); - exit(1); - } - if (mntflag & NTFS_MF_MOUNTED) { - if (!(mntflag & NTFS_MF_READONLY)) - err_exit("Device '%s' is mounted read-write. " - "You must 'umount' it first.\n", opt.volume); - if (!opt.ro_flag) - err_exit("Device '%s' is mounted. " - "You must 'umount' it first.\n", opt.volume); - } - /* - * Pass NTFS_MNT_FORENSIC so that the mount process does not modify the - * volume at all. We will do the logfile emptying and dirty setting - * later if needed. - */ - if (!(vol = ntfs_mount(opt.volume, opt.ro_flag | NTFS_MNT_FORENSIC))) { - int err = errno; - - perr_printf("Opening '%s' as NTFS failed", opt.volume); - if (err == EINVAL) - printf(invalid_ntfs_msg, opt.volume); - else if (err == EIO) - printf("%s", corrupt_volume_msg); - else if (err == EPERM) - printf("%s", hibernated_volume_msg); - else if (err == EOPNOTSUPP) - printf("%s", unclean_journal_msg); - else if (err == EBUSY) - printf("%s", opened_volume_msg); - exit(1); - } - - if (NVolWasDirty(vol)) - if (opt.force-- <= 0) - err_exit("Volume is scheduled for check.\nRun chkdsk /f" - " and please try again, or see option -f.\n"); - - if (NTFS_MAX_CLUSTER_SIZE < vol->cluster_size) - err_exit("Cluster size %u is too large!\n", - (unsigned int)vol->cluster_size); - - printf("Device name : %s\n", opt.volume); - printf("NTFS volume version: %d.%d\n", vol->major_ver, vol->minor_ver); - if (ntfs_version_is_supported(vol)) - perr_exit("Unknown NTFS version"); - - printf("Cluster size : %u bytes\n", - (unsigned int)vol->cluster_size); - print_vol_size("Current volume size", vol_size(vol, vol->nr_clusters)); - - return vol; -} - -/** - * prepare_volume_fixup - * - * Set the volume's dirty flag and wipe the filesystem journal. When Windows - * boots it will automatically run chkdsk to check for any problems. If the - * read-only command line option was given, this function will do nothing. - */ -static void prepare_volume_fixup(ntfs_volume *vol) -{ - printf("Schedule chkdsk for NTFS consistency check at Windows boot " - "time ...\n"); - vol->flags |= VOLUME_IS_DIRTY; - if (ntfs_volume_write_flags(vol, vol->flags)) - perr_exit("Failed to set the volume dirty"); - NVolSetWasDirty(vol); - if (vol->u.dev->d_ops->sync(vol->u.dev) == -1) - perr_exit("Failed to sync device"); - printf("Resetting $LogFile ... (this might take a while)\n"); - if (ntfs_logfile_reset(vol)) - perr_exit("Failed to reset $LogFile"); - if (vol->u.dev->d_ops->sync(vol->u.dev) == -1) - perr_exit("Failed to sync device"); -} - -static void set_disk_usage_constraint(ntfs_resize_t *resize) -{ - /* last lcn for a filled up volume (no empty space) */ - s64 last = resize->inuse - 1; - - if (resize->last_unsupp < last) - resize->last_unsupp = last; -} - -static void check_resize_constraints(ntfs_resize_t *resize) -{ - s64 new_size = resize->new_volume_size; - - /* FIXME: resize.shrink true also if only -i is used */ - if (!resize->shrink) - return; - - if (resize->inuse == resize->vol->nr_clusters) - err_exit("Volume is full. To shrink it, " - "delete unused files.\n"); - - if (opt.info) - return; - - /* FIXME: reserve some extra space so Windows can boot ... */ - if (new_size < resize->inuse) - err_exit("New size can't be less than the space already" - " occupied by data.\nYou either need to delete unused" - " files or see the -i option.\n"); - - if (new_size <= resize->last_unsupp) - err_exit("The fragmentation type, you have, isn't " - "supported yet. Rerun ntfsresize\nwith " - "the -i option to estimate the smallest " - "shrunken volume size supported.\n"); - - print_num_of_relocations(resize); -} - -static void check_cluster_allocation(ntfs_volume *vol, ntfsck_t *fsck) -{ - memset(fsck, 0, sizeof(ntfsck_t)); - - if (opt.show_progress) - fsck->flags |= NTFSCK_PROGBAR; - - if (setup_lcn_bitmap(&fsck->lcn_bitmap, vol->nr_clusters) != 0) - perr_exit("Failed to setup allocation bitmap"); - if (build_allocation_bitmap(vol, fsck) != 0) - exit(1); - if (fsck->outsider || fsck->multi_ref) { - err_printf("Filesystem check failed!\n"); - if (fsck->outsider) - err_printf("%d clusters are referenced outside " - "of the volume.\n", fsck->outsider); - if (fsck->multi_ref) - err_printf("%d clusters are referenced multiply" - " times.\n", fsck->multi_ref); - printf("%s", corrupt_volume_msg); - exit(1); - } - - compare_bitmaps(vol, &fsck->lcn_bitmap); -} - -int main(int argc, char **argv) -{ - ntfsck_t fsck; - ntfs_resize_t resize; - s64 new_size = 0; /* in clusters; 0 = --info w/o --size */ - s64 device_size; /* in bytes */ - ntfs_volume *vol; - - ntfs_log_set_handler(ntfs_log_handler_outerr); - - printf("%s v%s (libntfs %s)\n", EXEC_NAME, VERSION, - ntfs_libntfs_version()); - - if (!parse_options(argc, argv)) - return 1; - - utils_set_locale(); - - if (!(vol = mount_volume())) - err_exit("Couldn't open volume '%s'!\n", opt.volume); - - device_size = ntfs_device_size_get(vol->u.dev, vol->sector_size); - device_size *= vol->sector_size; - if (device_size <= 0) - err_exit("Couldn't get device size (%lld)!\n", device_size); - - print_vol_size("Current device size", device_size); - - if (device_size < vol->nr_clusters * vol->cluster_size) - err_exit("Current NTFS volume size is bigger than the device " - "size!\nCorrupt partition table or incorrect device " - "partitioning?\n"); - - if (!opt.bytes && !opt.info) - opt.bytes = device_size; - - /* Take the integer part: don't make the volume bigger than requested */ - new_size = opt.bytes / vol->cluster_size; - - /* Backup boot sector at the end of device isn't counted in NTFS - volume size thus we have to reserve space for it. */ - if (new_size) - --new_size; - - if (!opt.info) { - print_vol_size("New volume size ", vol_size(vol, new_size)); - if (device_size < opt.bytes) - err_exit("New size can't be bigger than the device size" - ".\nIf you want to enlarge NTFS then first " - "enlarge the device size by e.g. fdisk.\n"); - } - - if (!opt.info && (new_size == vol->nr_clusters || - (opt.bytes == device_size && - new_size == vol->nr_clusters - 1))) { - printf("Nothing to do: NTFS volume size is already OK.\n"); - exit(0); - } - - memset(&resize, 0, sizeof(resize)); - resize.vol = vol; - resize.new_volume_size = new_size; - /* This is also true if --info was used w/o --size (new_size = 0) */ - if (new_size < vol->nr_clusters) - resize.shrink = 1; - if (opt.show_progress) - resize.progress.flags |= NTFS_PROGBAR; - /* - * Checking and __reporting__ of bad sectors must be done before cluster - * allocation check because chkdsk doesn't fix $Bitmap's w/ bad sectors - * thus users would (were) quite confused why chkdsk doesn't work. - */ - resize.badclusters = check_bad_sectors(vol); - - check_cluster_allocation(vol, &fsck); - - print_disk_usage(vol, fsck.inuse); - - resize.inuse = fsck.inuse; - resize.lcn_bitmap = fsck.lcn_bitmap; - - set_resize_constraints(&resize); - set_disk_usage_constraint(&resize); - check_resize_constraints(&resize); - - if (opt.info) { - advise_on_resize(&resize); - exit(0); - } - - if (opt.force-- <= 0 && !opt.ro_flag) { - printf("%s", resize_warning_msg); - proceed_question(); - } - - /* FIXME: performance - relocate logfile here if it's needed */ - prepare_volume_fixup(vol); - - if (resize.relocations) - relocate_inodes(&resize); - - truncate_badclust_file(&resize); - truncate_bitmap_file(&resize); - update_bootsector(&resize); - - /* We don't create backup boot sector because we don't know where the - partition will be split. The scheduled chkdsk will fix it */ - - if (opt.ro_flag) { - printf("The read-only test run ended successfully.\n"); - exit(0); - } - - /* WARNING: don't modify the texts, external tools grep for them */ - printf("Syncing device ...\n"); - if (vol->u.dev->d_ops->sync(vol->u.dev) == -1) - perr_exit("fsync"); - - printf("Successfully resized NTFS on device '%s'.\n", vol->u.dev->d_name); - if (resize.shrink) - printf("%s", resize_important_msg); - - return 0; -} diff --git a/usr/src/cmd/ntfsprogs/ntfsundelete.c b/usr/src/cmd/ntfsprogs/ntfsundelete.c deleted file mode 100644 index 5b75aa0016..0000000000 --- a/usr/src/cmd/ntfsprogs/ntfsundelete.c +++ /dev/null @@ -1,2199 +0,0 @@ -/** - * ntfsundelete - Part of the Linux-NTFS project. - * - * Copyright (c) 2002-2005 Richard Russon - * Copyright (c) 2004-2005 Holger Ohmacht - * Copyright (c) 2005 Anton Altaparmakov - * Copyright (c) 2007 Yura Pakhuchiy - * - * This utility will recover deleted files from an NTFS volume. - * - * 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 Linux-NTFS - * 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_FEATURES_H -#include <features.h> -#endif -#ifdef HAVE_STDIO_H -#include <stdio.h> -#endif -#ifdef HAVE_STDLIB_H -#include <stdlib.h> -#endif -#ifdef HAVE_STRING_H -#include <string.h> -#endif -#ifdef HAVE_ERRNO_H -#include <errno.h> -#endif -#ifdef HAVE_SYS_TYPES_H -#include <sys/types.h> -#endif -#ifdef HAVE_SYS_STAT_H -#include <sys/stat.h> -#endif -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif -#ifdef HAVE_FCNTL_H -#include <fcntl.h> -#endif -#ifdef HAVE_GETOPT_H -#include <getopt.h> -#endif -#ifdef HAVE_TIME_H -#include <time.h> -#endif -#ifdef HAVE_LIMITS_H -#include <limits.h> -#endif -#ifdef HAVE_STDARG_H -#include <stdarg.h> -#endif -#ifdef HAVE_UTIME_H -#include <utime.h> -#endif -#include <regex.h> - -#if !defined(REG_NOERROR) || (REG_NOERROR != 0) -#define REG_NOERROR 0 -#endif - -#include "compat.h" -#include "ntfsundelete.h" -#include "bootsect.h" -#include "mft.h" -#include "attrib.h" -#include "layout.h" -#include "inode.h" -#include "device.h" -#include "utils.h" -#include "debug.h" -#include "ntfstime.h" -#include "version.h" -#include "logging.h" - -static const char *EXEC_NAME = "ntfsundelete"; -static const char *MFTFILE = "mft"; -static const char *UNNAMED = "<unnamed>"; -static const char *NONE = "<none>"; -static const char *UNKNOWN = "unknown"; -static struct options opts; - -typedef struct -{ - u32 begin; - u32 end; -} range; - -static short with_regex; /* Flag Regular expression available */ -static short avoid_duplicate_printing; /* Flag No duplicate printing of file infos */ -static range *ranges; /* Array containing all Inode-Ranges for undelete */ -static long nr_entries; /* Number of range entries */ - -/** - * parse_inode_arg - parses the inode expression - * - * Parses the optarg after parameter -u for valid ranges - * - * Return: Number of correct inode specifications or -1 for error - */ -static int parse_inode_arg(void) -{ - int p; - u32 imax; - u32 range_begin; - u32 range_end; - u32 range_temp; - u32 inode; - char *opt_arg_ptr; - char *opt_arg_temp; - char *opt_arg_end1; - char *opt_arg_end2; - - /* Check whether optarg is available or not */ - nr_entries = 0; - if (optarg == NULL) - return (0); /* bailout if no optarg */ - - /* init variables */ - p = strlen(optarg); - imax = p; - opt_arg_ptr = optarg; - opt_arg_end1 = optarg; - opt_arg_end2 = &(optarg[p]); - - /* alloc mem for range table */ - ranges = (range *) malloc((p + 1) * sizeof(range)); - if (ranges == NULL) { - ntfs_log_error("ERROR: Couldn't alloc mem for parsing inodes!\n"); - return (-1); - } - - /* loop */ - while ((opt_arg_end1 != opt_arg_end2) && (p > 0)) { - /* Try to get inode */ - inode = strtoul(opt_arg_ptr, &opt_arg_end1, 0); - p--; - - /* invalid char at begin */ - if ((opt_arg_ptr == opt_arg_end1) || (opt_arg_ptr == opt_arg_end2)) { - ntfs_log_error("ERROR: Invalid Number: %s\n", opt_arg_ptr); - return (-1); - } - - /* RANGE - Check for range */ - if (opt_arg_end1[0] == '-') { - /* get range end */ - opt_arg_temp = opt_arg_end1; - opt_arg_end1 = & (opt_arg_temp[1]); - if (opt_arg_temp >= opt_arg_end2) { - ntfs_log_error("ERROR: Missing range end!\n"); - return (-1); - } - range_begin = inode; - - /* get count */ - range_end = strtoul(opt_arg_end1, &opt_arg_temp, 0); - if (opt_arg_temp == opt_arg_end1) { - ntfs_log_error("ERROR: Invalid Number: %s\n", opt_arg_temp); - return (-1); - } - - /* check for correct values */ - if (range_begin > range_end) { - range_temp = range_end; - range_end = range_begin; - range_begin = range_temp; - } - - /* put into struct */ - ranges[nr_entries].begin = range_begin; - ranges[nr_entries].end = range_end; - nr_entries++; - - /* Last check */ - opt_arg_ptr = & (opt_arg_temp[1]); - if (opt_arg_ptr >= opt_arg_end2) - break; - } else if (opt_arg_end1[0] == ',') { - /* SINGLE VALUE, BUT CONTINUING */ - /* put inode into range list */ - ranges[nr_entries].begin = inode; - ranges[nr_entries].end = inode; - nr_entries++; - - /* Next inode */ - opt_arg_ptr = & (opt_arg_end1[1]); - if (opt_arg_ptr >= opt_arg_end2) { - ntfs_log_error("ERROR: Missing new value at end of input!\n"); - return (-1); - } - continue; - } else { /* SINGLE VALUE, END */ - ranges[nr_entries].begin = inode; - ranges[nr_entries].end = inode; - nr_entries++; - } - } - return (nr_entries); -} - -/** - * version - Print version information about the program - * - * Print a copyright statement and a brief description of the program. - * - * Return: none - */ -static void version(void) -{ - ntfs_log_info("\n%s v%s (libntfs %s) - Recover deleted files from an " - "NTFS Volume.\n\n", EXEC_NAME, VERSION, - ntfs_libntfs_version()); - ntfs_log_info("Copyright (c) 2002-2005 Richard Russon\n" - "Copyright (c) 2004-2005 Holger Ohmacht\n" - "Copyright (c) 2005 Anton Altaparmakov\n" - "Copyright (c) 2007 Yura Pakhuchiy\n"); - ntfs_log_info("\n%s\n%s%s\n", ntfs_gpl, ntfs_bugs, ntfs_home); -} - -/** - * usage - Print a list of the parameters to the program - * - * Print a list of the parameters and options for the program. - * - * Return: none - */ -static void usage(void) -{ - ntfs_log_info("\nUsage: %s [options] device\n" - " -s, --scan Scan for files (default)\n" - " -p, --percentage NUM Minimum percentage recoverable\n" - " -m, --match PATTERN Only work on files with matching names\n" - " -C, --case Case sensitive matching\n" - " -S, --size RANGE Match files of this size\n" - " -t, --time SINCE Last referenced since this time\n" - "\n" - " -u, --undelete Undelete mode\n" - " -i, --inodes RANGE Recover these inodes\n" - //" -I, --interactive Interactive mode\n" - " -o, --output FILE Save with this filename\n" - " -O, --optimistic Undelete in-use clusters as well\n" - " -d, --destination DIR Destination directory\n" - " -b, --byte NUM Fill missing parts with this byte\n" - " -T, --truncate Truncate 100%% recoverable file to exact size.\n" - " -P, --parent Show parent directory\n" - "\n" - " -c, --copy RANGE Write a range of MFT records to a file\n" - "\n" - " -f, --force Use less caution\n" - " -q, --quiet Less output\n" - " -v, --verbose More output\n" - " -V, --version Display version information\n" - " -h, --help Display this help\n\n", - EXEC_NAME); - ntfs_log_info("%s%s\n", ntfs_bugs, ntfs_home); -} - -/** - * transform - Convert a shell style pattern to a regex - * @pattern: String to be converted - * @regex: Resulting regular expression is put here - * - * This will transform patterns, such as "*.doc" to true regular expressions. - * The function will also place '^' and '$' around the expression to make it - * behave as the user would expect - * - * Before After - * . \. - * * .* - * ? . - * - * Notes: - * The returned string must be freed by the caller. - * If transform fails, @regex will not be changed. - * - * Return: 1, Success, the string was transformed - * 0, An error occurred - */ -static int transform(const char *pattern, char **regex) -{ - char *result; - int length, i, j; - - if (!pattern || !regex) - return 0; - - length = strlen(pattern); - if (length < 1) { - ntfs_log_error("Pattern to transform is empty\n"); - return 0; - } - - for (i = 0; pattern[i]; i++) { - if ((pattern[i] == '*') || (pattern[i] == '.')) - length++; - } - - result = malloc(length + 3); - if (!result) { - ntfs_log_error("Couldn't allocate memory in transform()\n"); - return 0; - } - - result[0] = '^'; - - for (i = 0, j = 1; pattern[i]; i++, j++) { - if (pattern[i] == '*') { - result[j] = '.'; - j++; - result[j] = '*'; - } else if (pattern[i] == '.') { - result[j] = '\\'; - j++; - result[j] = '.'; - } else if (pattern[i] == '?') { - result[j] = '.'; - } else { - result[j] = pattern[i]; - } - } - - result[j] = '$'; - result[j+1] = 0; - ntfs_log_debug("Pattern '%s' replaced with regex '%s'.\n", pattern, - result); - - *regex = result; - return 1; -} - -/** - * parse_time - Convert a time abbreviation to seconds - * @string: The string to be converted - * @since: The absolute time referred to - * - * Strings representing times will be converted into a time_t. The numbers will - * be regarded as seconds unless suffixed. - * - * Suffix Description - * [yY] Year - * [mM] Month - * [wW] Week - * [dD] Day - * [sS] Second - * - * Therefore, passing "1W" will return the time_t representing 1 week ago. - * - * Notes: - * Only the first character of the suffix is read. - * If parse_time fails, @since will not be changed - * - * Return: 1 Success - * 0 Error, the string was malformed - */ -static int parse_time(const char *value, time_t *since) -{ - long long result; - time_t now; - char *suffix = NULL; - - if (!value || !since) - return -1; - - ntfs_log_trace("Parsing time '%s' ago.\n", value); - - result = strtoll(value, &suffix, 10); - if (result < 0 || errno == ERANGE) { - ntfs_log_error("Invalid time '%s'.\n", value); - return 0; - } - - if (!suffix) { - ntfs_log_error("Internal error, strtoll didn't return a suffix.\n"); - return 0; - } - - if (strlen(suffix) > 1) { - ntfs_log_error("Invalid time suffix '%s'. Use Y, M, W, D or H.\n", suffix); - return 0; - } - - switch (suffix[0]) { - case 'y': case 'Y': result *= 12; - case 'm': case 'M': result *= 4; - case 'w': case 'W': result *= 7; - case 'd': case 'D': result *= 24; - case 'h': case 'H': result *= 3600; - case 0: - break; - - default: - ntfs_log_error("Invalid time suffix '%s'. Use Y, M, W, D or H.\n", suffix); - return 0; - } - - now = time(NULL); - - ntfs_log_debug("Time now = %lld, Time then = %lld.\n", (long long) now, - (long long) result); - *since = now - result; - return 1; -} - -/** - * parse_options - Read and validate the programs command line - * - * Read the command line, verify the syntax and parse the options. - * This function is very long, but quite simple. - * - * Return: 1 Success - * 0 Error, one or more problems - */ -static int parse_options(int argc, char *argv[]) -{ - static const char *sopt = "-b:Cc:d:fh?i:m:o:OPp:sS:t:TuqvV"; - static const struct option lopt[] = { - { "byte", required_argument, NULL, 'b' }, - { "case", no_argument, NULL, 'C' }, - { "copy", required_argument, NULL, 'c' }, - { "destination", required_argument, NULL, 'd' }, - { "force", no_argument, NULL, 'f' }, - { "help", no_argument, NULL, 'h' }, - { "inodes", required_argument, NULL, 'i' }, - //{ "interactive", no_argument, NULL, 'I' }, - { "match", required_argument, NULL, 'm' }, - { "optimistic", no_argument, NULL, 'O' }, - { "output", required_argument, NULL, 'o' }, - { "parent", no_argument, NULL, 'P' }, - { "percentage", required_argument, NULL, 'p' }, - { "quiet", no_argument, NULL, 'q' }, - { "scan", no_argument, NULL, 's' }, - { "size", required_argument, NULL, 'S' }, - { "time", required_argument, NULL, 't' }, - { "truncate", no_argument, NULL, 'T' }, - { "undelete", no_argument, NULL, 'u' }, - { "verbose", no_argument, NULL, 'v' }, - { "version", no_argument, NULL, 'V' }, - { NULL, 0, NULL, 0 } - }; - - int c = -1; - char *end = NULL; - int err = 0; - int ver = 0; - int help = 0; - int levels = 0; - - opterr = 0; /* We'll handle the errors, thank you. */ - - opts.mode = MODE_NONE; - opts.uinode = -1; - opts.percent = -1; - opts.fillbyte = -1; - while ((c = getopt_long(argc, argv, sopt, lopt, NULL)) != -1) { - switch (c) { - case 1: /* A non-option argument */ - if (!opts.device) { - opts.device = argv[optind-1]; - } else { - opts.device = NULL; - err++; - } - break; - case 'b': - if (opts.fillbyte == (char)-1) { - end = NULL; - opts.fillbyte = strtol(optarg, &end, 0); - if (end && *end) - err++; - } else { - err++; - } - break; - case 'C': - opts.match_case++; - break; - case 'c': - if (opts.mode == MODE_NONE) { - if (!utils_parse_range(optarg, - &opts.mft_begin, &opts.mft_end, TRUE)) - err++; - opts.mode = MODE_COPY; - } else { - opts.mode = MODE_ERROR; - } - break; - case 'd': - if (!opts.dest) - opts.dest = optarg; - else - err++; - break; - case 'f': - opts.force++; - break; - case 'h': - case '?': - if (ntfs_log_parse_option (argv[optind-1])) - break; - help++; - break; - case 'i': - end = NULL; - /* parse inodes */ - if (parse_inode_arg() == -1) - err++; - if (end && *end) - err++; - break; - case 'm': - if (!opts.match) { - if (!transform(optarg, &opts.match)) { - err++; - } else { - /* set regex-flag on true ;) */ - with_regex= 1; - } - } else { - err++; - } - break; - case 'o': - if (!opts.output) { - opts.output = optarg; - } else { - err++; - } - break; - case 'O': - if (!opts.optimistic) { - opts.optimistic++; - } else { - err++; - } - break; - case 'P': - if (!opts.parent) { - opts.parent++; - } else { - err++; - } - break; - case 'p': - if (opts.percent == -1) { - end = NULL; - opts.percent = strtol(optarg, &end, 0); - if (end && ((*end != '%') && (*end != 0))) - err++; - } else { - err++; - } - break; - case 'q': - opts.quiet++; - ntfs_log_clear_levels(NTFS_LOG_LEVEL_QUIET); - break; - case 's': - if (opts.mode == MODE_NONE) - opts.mode = MODE_SCAN; - else - opts.mode = MODE_ERROR; - break; - case 'S': - if ((opts.size_begin > 0) || (opts.size_end > 0) || - !utils_parse_range(optarg, &opts.size_begin, - &opts.size_end, TRUE)) { - err++; - } - break; - case 't': - if (opts.since == 0) { - if (!parse_time(optarg, &opts.since)) - err++; - } else { - err++; - } - break; - case 'T': - opts.truncate++; - break; - case 'u': - if (opts.mode == MODE_NONE) { - opts.mode = MODE_UNDELETE; - } else { - opts.mode = MODE_ERROR; - } - break; - case 'v': - opts.verbose++; - ntfs_log_set_levels(NTFS_LOG_LEVEL_VERBOSE); - break; - case 'V': - ver++; - break; - default: - if (((optopt == 'b') || (optopt == 'c') || - (optopt == 'd') || (optopt == 'm') || - (optopt == 'o') || (optopt == 'p') || - (optopt == 'S') || (optopt == 't') || - (optopt == 'u')) && (!optarg)) { - ntfs_log_error("Option '%s' requires an argument.\n", argv[optind-1]); - } else { - ntfs_log_error("Unknown option '%s'.\n", argv[optind-1]); - } - err++; - break; - } - } - - /* Make sure we're in sync with the log levels */ - levels = ntfs_log_get_levels(); - if (levels & NTFS_LOG_LEVEL_VERBOSE) - opts.verbose++; - if (!(levels & NTFS_LOG_LEVEL_QUIET)) - opts.quiet++; - - if (help || ver) { - opts.quiet = 0; - } else { - if (opts.device == NULL) { - if (argc > 1) - ntfs_log_error("You must specify exactly one device.\n"); - err++; - } - - if (opts.mode == MODE_NONE) { - opts.mode = MODE_SCAN; - } - - switch (opts.mode) { - case MODE_SCAN: - if (opts.output || opts.dest || opts.truncate || - (opts.fillbyte != (char)-1)) { - ntfs_log_error("Scan can only be used with --percent, " - "--match, --ignore-case, --size and --time.\n"); - err++; - } - if (opts.match_case && !opts.match) { - ntfs_log_error("The --case option doesn't make sense without the --match option\n"); - err++; - } - break; - - case MODE_UNDELETE: - /*if ((opts.percent != -1) || (opts.size_begin > 0) || (opts.size_end > 0)) { - ntfs_log_error("Undelete can only be used with " - "--output, --destination, --byte and --truncate.\n"); - err++; - }*/ - break; - case MODE_COPY: - if ((opts.fillbyte != (char)-1) || opts.truncate || - (opts.percent != -1) || - opts.match || opts.match_case || - (opts.size_begin > 0) || - (opts.size_end > 0)) { - ntfs_log_error("Copy can only be used with --output and --destination.\n"); - err++; - } - break; - default: - ntfs_log_error("You can only select one of Scan, Undelete or Copy.\n"); - err++; - } - - if ((opts.percent < -1) || (opts.percent > 100)) { - ntfs_log_error("Percentage value must be in the range 0 - 100.\n"); - err++; - } - - if (opts.quiet) { - if (opts.verbose) { - ntfs_log_error("You may not use --quiet and --verbose at the same time.\n"); - err++; - } else if (opts.mode == MODE_SCAN) { - ntfs_log_error("You may not use --quiet when scanning a volume.\n"); - err++; - } - } - - if (opts.parent && !opts.verbose) { - ntfs_log_error("To use --parent, you must also use --verbose.\n"); - err++; - } - } - - if (opts.fillbyte == (char)-1) - opts.fillbyte = 0; - - if (ver) - version(); - if (help || err) - usage(); - - return (!err && !help && !ver); -} - -/** - * free_file - Release the resources used by a file object - * @file: The unwanted file object - * - * This will free up the memory used by a file object and iterate through the - * object's children, freeing their resources too. - * - * Return: none - */ -static void free_file(struct ufile *file) -{ - struct list_head *item, *tmp; - - if (!file) - return; - - list_for_each_safe(item, tmp, &file->name) { /* List of filenames */ - struct filename *f = list_entry(item, struct filename, list); - ntfs_log_debug("freeing filename '%s'", f->name ? f->name : - NONE); - if (f->name) - free(f->name); - if (f->parent_name) { - ntfs_log_debug(" and parent filename '%s'", - f->parent_name); - free(f->parent_name); - } - ntfs_log_debug(".\n"); - free(f); - } - - list_for_each_safe(item, tmp, &file->data) { /* List of data streams */ - struct data *d = list_entry(item, struct data, list); - ntfs_log_debug("Freeing data stream '%s'.\n", d->name ? - d->name : UNNAMED); - if (d->name) - free(d->name); - if (d->runlist) - free(d->runlist); - free(d); - } - - free(file->mft); - free(file); -} - -/** - * verify_parent - confirm a record is parent of a file - * @name: a filename of the file - * @rec: the mft record of the possible parent - * - * Check that @rec is the parent of the file represented by @name. - * If @rec is a directory, but it is created after @name, then we - * can't determine whether @rec is really @name's parent. - * - * Return: @rec's filename, either same name space as @name or lowest space. - * NULL if can't determine parenthood or on error. - */ -static FILE_NAME_ATTR* verify_parent(struct filename* name, MFT_RECORD* rec) -{ - ATTR_RECORD *attr30; - FILE_NAME_ATTR *filename_attr = NULL, *lowest_space_name = NULL; - ntfs_attr_search_ctx *ctx; - int found_same_space = 1; - - if (!name || !rec) - return NULL; - - if (!(rec->flags & MFT_RECORD_IS_DIRECTORY)) { - return NULL; - } - - ctx = ntfs_attr_get_search_ctx(NULL, rec); - if (!ctx) { - ntfs_log_error("ERROR: Couldn't create a search context.\n"); - return NULL; - } - - attr30 = find_attribute(AT_FILE_NAME, ctx); - if (!attr30) { - return NULL; - } - - filename_attr = (FILE_NAME_ATTR*)((char*)attr30 + le16_to_cpu(attr30->u.res.value_offset)); - /* if name is older than this dir -> can't determine */ - if (ntfs2utc(filename_attr->creation_time) > name->date_c) { - return NULL; - } - - if (filename_attr->file_name_type != name->name_space) { - found_same_space = 0; - lowest_space_name = filename_attr; - - while (!found_same_space && (attr30 = find_attribute(AT_FILE_NAME, ctx))) { - filename_attr = (FILE_NAME_ATTR*)((char*)attr30 + le16_to_cpu(attr30->u.res.value_offset)); - - if (filename_attr->file_name_type == name->name_space) { - found_same_space = 1; - } else { - if (filename_attr->file_name_type < lowest_space_name->file_name_type) { - lowest_space_name = filename_attr; - } - } - } - } - - ntfs_attr_put_search_ctx(ctx); - - return (found_same_space ? filename_attr : lowest_space_name); -} - -/** - * get_parent_name - Find the name of a file's parent. - * @name: the filename whose parent's name to find - */ -static void get_parent_name(struct filename* name, ntfs_volume* vol) -{ - ntfs_attr* mft_data; - MFT_RECORD* rec; - FILE_NAME_ATTR* filename_attr; - long long inode_num; - - if (!name || !vol) - return; - - rec = calloc(1, vol->mft_record_size); - if (!rec) { - ntfs_log_error("ERROR: Couldn't allocate memory in " - "get_parent_name()\n"); - return; - } - - mft_data = ntfs_attr_open(vol->mft_ni, AT_DATA, AT_UNNAMED, 0); - if (!mft_data) { - ntfs_log_perror("ERROR: Couldn't open $MFT/$DATA"); - } else { - inode_num = MREF_LE(name->parent_mref); - - if (ntfs_attr_pread(mft_data, vol->mft_record_size * inode_num, - vol->mft_record_size, rec) < 1) { - ntfs_log_error("ERROR: Couldn't read MFT Record %lld" - ".\n", inode_num); - } else if ((filename_attr = verify_parent(name, rec))) { - if (ntfs_ucstombs(filename_attr->file_name, - filename_attr->file_name_length, - &name->parent_name, 0) < 0) { - ntfs_log_debug("ERROR: Couldn't translate " - "filename to current " - "locale.\n"); - name->parent_name = NULL; - } - } - } - - if (mft_data) { - ntfs_attr_close(mft_data); - } - - if (rec) { - free(rec); - } - - return; -} - -/** - * get_filenames - Read an MFT Record's $FILENAME attributes - * @file: The file object to work with - * - * A single file may have more than one filename. This is quite common. - * Windows creates a short DOS name for each long name, e.g. LONGFI~1.XYZ, - * LongFiLeName.xyZ. - * - * The filenames that are found are put in filename objects and added to a - * linked list of filenames in the file object. For convenience, the unicode - * filename is converted into the current locale and stored in the filename - * object. - * - * One of the filenames is picked (the one with the lowest numbered namespace) - * and its locale friendly name is put in pref_name. - * - * Return: n The number of $FILENAME attributes found - * -1 Error - */ -static int get_filenames(struct ufile *file, ntfs_volume* vol) -{ - ATTR_RECORD *rec; - FILE_NAME_ATTR *attr; - ntfs_attr_search_ctx *ctx; - struct filename *name; - int count = 0; - int space = 4; - - if (!file) - return -1; - - ctx = ntfs_attr_get_search_ctx(NULL, file->mft); - if (!ctx) - return -1; - - while ((rec = find_attribute(AT_FILE_NAME, ctx))) { - /* We know this will always be resident. */ - attr = (FILE_NAME_ATTR *)((char *)rec + - le16_to_cpu(rec->u.res.value_offset)); - - name = calloc(1, sizeof(*name)); - if (!name) { - ntfs_log_error("ERROR: Couldn't allocate memory in " - "get_filenames().\n"); - count = -1; - break; - } - - name->uname = attr->file_name; - name->uname_len = attr->file_name_length; - name->name_space = attr->file_name_type; - name->size_alloc = sle64_to_cpu(attr->allocated_size); - name->size_data = sle64_to_cpu(attr->data_size); - name->flags = attr->file_attributes; - - name->date_c = ntfs2utc(attr->creation_time); - name->date_a = ntfs2utc(attr->last_data_change_time); - name->date_m = ntfs2utc(attr->last_mft_change_time); - name->date_r = ntfs2utc(attr->last_access_time); - - if (ntfs_ucstombs(name->uname, name->uname_len, &name->name, - 0) < 0) { - ntfs_log_debug("ERROR: Couldn't translate filename to " - "current locale.\n"); - } - - name->parent_name = NULL; - - if (opts.parent) { - name->parent_mref = attr->parent_directory; - get_parent_name(name, vol); - } - - if (name->name_space < space) { - file->pref_name = name->name; - file->pref_pname = name->parent_name; - space = name->name_space; - } - - file->max_size = max(file->max_size, name->size_alloc); - file->max_size = max(file->max_size, name->size_data); - - list_add_tail(&name->list, &file->name); - count++; - } - - ntfs_attr_put_search_ctx(ctx); - ntfs_log_debug("File has %d names.\n", count); - return count; -} - -/** - * get_data - Read an MFT Record's $DATA attributes - * @file: The file object to work with - * @vol: An ntfs volume obtained from ntfs_mount - * - * A file may have more than one data stream. All files will have an unnamed - * data stream which contains the file's data. Some Windows applications store - * extra information in a separate stream. - * - * The streams that are found are put in data objects and added to a linked - * list of data streams in the file object. - * - * Return: n The number of $FILENAME attributes found - * -1 Error - */ -static int get_data(struct ufile *file, ntfs_volume *vol) -{ - ATTR_RECORD *rec; - ntfs_attr_search_ctx *ctx; - int count = 0; - struct data *data; - - if (!file) - return -1; - - ctx = ntfs_attr_get_search_ctx(NULL, file->mft); - if (!ctx) - return -1; - - while ((rec = find_attribute(AT_DATA, ctx))) { - data = calloc(1, sizeof(*data)); - if (!data) { - ntfs_log_error("ERROR: Couldn't allocate memory in " - "get_data().\n"); - count = -1; - break; - } - - data->resident = !rec->non_resident; - data->compressed = (rec->flags & ATTR_IS_COMPRESSED) ? 1 : 0; - data->encrypted = (rec->flags & ATTR_IS_ENCRYPTED) ? 1 : 0; - - if (rec->name_length) { - data->uname = (ntfschar *)((char *)rec + - le16_to_cpu(rec->name_offset)); - data->uname_len = rec->name_length; - - if (ntfs_ucstombs(data->uname, data->uname_len, - &data->name, 0) < 0) { - ntfs_log_error("ERROR: Cannot translate name " - "into current locale.\n"); - } - } - - if (data->resident) { - data->size_data = le32_to_cpu(rec->u.res.value_length); - data->data = (char*)rec + - le16_to_cpu(rec->u.res.value_offset); - } else { - data->size_alloc = sle64_to_cpu(rec->u.nonres.allocated_size); - data->size_data = sle64_to_cpu(rec->u.nonres.data_size); - data->size_init = sle64_to_cpu(rec->u.nonres.initialized_size); - data->size_vcn = sle64_to_cpu(rec->u.nonres.highest_vcn) + 1; - } - - data->runlist = ntfs_mapping_pairs_decompress(vol, rec, NULL); - if (!data->runlist) { - ntfs_log_debug("Couldn't decompress the data runs.\n"); - } - - file->max_size = max(file->max_size, data->size_data); - file->max_size = max(file->max_size, data->size_init); - - list_add_tail(&data->list, &file->data); - count++; - } - - ntfs_attr_put_search_ctx(ctx); - ntfs_log_debug("File has %d data streams.\n", count); - return count; -} - -/** - * read_record - Read an MFT record into memory - * @vol: An ntfs volume obtained from ntfs_mount - * @record: The record number to read - * - * Read the specified MFT record and gather as much information about it as - * possible. - * - * Return: Pointer A ufile object containing the results - * NULL Error - */ -static struct ufile * read_record(ntfs_volume *vol, long long record) -{ - ATTR_RECORD *attr10, *attr20, *attr90; - struct ufile *file; - ntfs_attr *mft; - - if (!vol) - return NULL; - - file = calloc(1, sizeof(*file)); - if (!file) { - ntfs_log_error("ERROR: Couldn't allocate memory in read_record()\n"); - return NULL; - } - - INIT_LIST_HEAD(&file->name); - INIT_LIST_HEAD(&file->data); - file->inode = record; - - file->mft = malloc(vol->mft_record_size); - if (!file->mft) { - ntfs_log_error("ERROR: Couldn't allocate memory in read_record()\n"); - free_file(file); - return NULL; - } - - mft = ntfs_attr_open(vol->mft_ni, AT_DATA, AT_UNNAMED, 0); - if (!mft) { - ntfs_log_perror("ERROR: Couldn't open $MFT/$DATA"); - free_file(file); - return NULL; - } - - if (ntfs_attr_mst_pread(mft, vol->mft_record_size * record, 1, vol->mft_record_size, file->mft) < 1) { - ntfs_log_error("ERROR: Couldn't read MFT Record %lld.\n", record); - ntfs_attr_close(mft); - free_file(file); - return NULL; - } - - ntfs_attr_close(mft); - mft = NULL; - - attr10 = find_first_attribute(AT_STANDARD_INFORMATION, file->mft); - attr20 = find_first_attribute(AT_ATTRIBUTE_LIST, file->mft); - attr90 = find_first_attribute(AT_INDEX_ROOT, file->mft); - - ntfs_log_debug("Attributes present: %s %s %s.\n", attr10?"0x10":"", - attr20?"0x20":"", attr90?"0x90":""); - - if (attr10) { - STANDARD_INFORMATION *si; - si = (STANDARD_INFORMATION *) ((char *) attr10 + le16_to_cpu(attr10->u.res.value_offset)); - file->date = ntfs2utc(si->last_data_change_time); - } - - if (attr20 || !attr10) - file->attr_list = 1; - if (attr90) - file->directory = 1; - - if (get_filenames(file, vol) < 0) { - ntfs_log_error("ERROR: Couldn't get filenames.\n"); - } - if (get_data(file, vol) < 0) { - ntfs_log_error("ERROR: Couldn't get data streams.\n"); - } - - return file; -} - -/** - * calc_percentage - Calculate how much of the file is recoverable - * @file: The file object to work with - * @vol: An ntfs volume obtained from ntfs_mount - * - * Read through all the $DATA streams and determine if each cluster in each - * stream is still free disk space. This is just measuring the potential for - * recovery. The data may have still been overwritten by a another file which - * was then deleted. - * - * Files with a resident $DATA stream will have a 100% potential. - * - * N.B. If $DATA attribute spans more than one MFT record (i.e. badly - * fragmented) then only the data in this segment will be used for the - * calculation. - * - * N.B. Currently, compressed and encrypted files cannot be recovered, so they - * will return 0%. - * - * Return: n The percentage of the file that _could_ be recovered - * -1 Error - */ -static int calc_percentage(struct ufile *file, ntfs_volume *vol) -{ - runlist_element *rl = NULL; - struct list_head *pos; - struct data *data; - long long i, j; - long long start, end; - int clusters_inuse, clusters_free; - int percent = 0; - - if (!file || !vol) - return -1; - - if (file->directory) { - ntfs_log_debug("Found a directory: not recoverable.\n"); - return 0; - } - - if (list_empty(&file->data)) { - ntfs_log_verbose("File has no data streams.\n"); - return 0; - } - - list_for_each(pos, &file->data) { - data = list_entry(pos, struct data, list); - clusters_inuse = 0; - clusters_free = 0; - - if (data->encrypted) { - ntfs_log_verbose("File is encrypted, recovery is " - "impossible.\n"); - continue; - } - - if (data->compressed) { - ntfs_log_verbose("File is compressed, recovery not yet " - "implemented.\n"); - continue; - } - - if (data->resident) { - ntfs_log_verbose("File is resident, therefore " - "recoverable.\n"); - percent = 100; - data->percent = 100; - continue; - } - - rl = data->runlist; - if (!rl) { - ntfs_log_verbose("File has no runlist, hence no data." - "\n"); - continue; - } - - if (rl[0].length <= 0) { - ntfs_log_verbose("File has an empty runlist, hence no " - "data.\n"); - continue; - } - - if (rl[0].lcn == LCN_RL_NOT_MAPPED) { /* extended mft record */ - ntfs_log_verbose("Missing segment at beginning, %lld " - "clusters\n", (long long)rl[0].length); - clusters_inuse += rl[0].length; - rl++; - } - - for (i = 0; rl[i].length > 0; i++) { - if (rl[i].lcn == LCN_RL_NOT_MAPPED) { - ntfs_log_verbose("Missing segment at end, %lld " - "clusters\n", - (long long)rl[i].length); - clusters_inuse += rl[i].length; - continue; - } - - if (rl[i].lcn == LCN_HOLE) { - clusters_free += rl[i].length; - continue; - } - - start = rl[i].lcn; - end = rl[i].lcn + rl[i].length; - - for (j = start; j < end; j++) { - if (utils_cluster_in_use(vol, j)) - clusters_inuse++; - else - clusters_free++; - } - } - - if ((clusters_inuse + clusters_free) == 0) { - ntfs_log_error("ERROR: Unexpected error whilst " - "calculating percentage for inode %lld\n", - file->inode); - continue; - } - - data->percent = (clusters_free * 100) / - (clusters_inuse + clusters_free); - - percent = max(percent, data->percent); - } - - ntfs_log_verbose("File is %d%% recoverable\n", percent); - return percent; -} - -/** - * dump_record - Print everything we know about an MFT record - * @file: The file to work with - * - * Output the contents of the file object. This will print everything that has - * been read from the MFT record, or implied by various means. - * - * Because of the redundant nature of NTFS, there will be some duplication of - * information, though it will have been read from different sources. - * - * N.B. If the filename is missing, or couldn't be converted to the current - * locale, "<none>" will be displayed. - * - * Return: none - */ -static void dump_record(struct ufile *file) -{ - char buffer[20]; - const char *name; - struct list_head *item; - int i; - - if (!file) - return; - - ntfs_log_quiet("MFT Record %lld\n", file->inode); - ntfs_log_quiet("Type: %s\n", (file->directory) ? "Directory" : "File"); - strftime(buffer, sizeof(buffer), "%F %R", localtime(&file->date)); - ntfs_log_quiet("Date: %s\n", buffer); - - if (file->attr_list) - ntfs_log_quiet("Metadata may span more than one MFT record\n"); - - list_for_each(item, &file->name) { - struct filename *f = list_entry(item, struct filename, list); - - if (f->name) - name = f->name; - else - name = NONE; - - ntfs_log_quiet("Filename: (%d) %s\n", f->name_space, f->name); - ntfs_log_quiet("File Flags: "); - if (f->flags & FILE_ATTR_SYSTEM) - ntfs_log_quiet("System "); - if (f->flags & FILE_ATTR_DIRECTORY) - ntfs_log_quiet("Directory "); - if (f->flags & FILE_ATTR_SPARSE_FILE) - ntfs_log_quiet("Sparse "); - if (f->flags & FILE_ATTR_REPARSE_POINT) - ntfs_log_quiet("Reparse "); - if (f->flags & FILE_ATTR_COMPRESSED) - ntfs_log_quiet("Compressed "); - if (f->flags & FILE_ATTR_ENCRYPTED) - ntfs_log_quiet("Encrypted "); - if (!(f->flags & (FILE_ATTR_SYSTEM | FILE_ATTR_DIRECTORY | - FILE_ATTR_SPARSE_FILE | FILE_ATTR_REPARSE_POINT | - FILE_ATTR_COMPRESSED | FILE_ATTR_ENCRYPTED))) { - ntfs_log_quiet("%s", NONE); - } - - ntfs_log_quiet("\n"); - - if (opts.parent) { - ntfs_log_quiet("Parent: %s\n", f->parent_name ? - f->parent_name : "<non-determined>"); - } - - ntfs_log_quiet("Size alloc: %lld\n", f->size_alloc); - ntfs_log_quiet("Size data: %lld\n", f->size_data); - - strftime(buffer, sizeof(buffer), "%F %R", - localtime(&f->date_c)); - ntfs_log_quiet("Date C: %s\n", buffer); - strftime(buffer, sizeof(buffer), "%F %R", - localtime(&f->date_a)); - ntfs_log_quiet("Date A: %s\n", buffer); - strftime(buffer, sizeof(buffer), "%F %R", - localtime(&f->date_m)); - ntfs_log_quiet("Date M: %s\n", buffer); - strftime(buffer, sizeof(buffer), "%F %R", - localtime(&f->date_r)); - ntfs_log_quiet("Date R: %s\n", buffer); - } - - ntfs_log_quiet("Data Streams:\n"); - list_for_each(item, &file->data) { - struct data *d = list_entry(item, struct data, list); - ntfs_log_quiet("Name: %s\n", (d->name) ? d->name : UNNAMED); - ntfs_log_quiet("Flags: "); - if (d->resident) ntfs_log_quiet("Resident\n"); - if (d->compressed) ntfs_log_quiet("Compressed\n"); - if (d->encrypted) ntfs_log_quiet("Encrypted\n"); - if (!d->resident && !d->compressed && !d->encrypted) - ntfs_log_quiet("None\n"); - else - ntfs_log_quiet("\n"); - - ntfs_log_quiet("Size alloc: %lld\n", d->size_alloc); - ntfs_log_quiet("Size data: %lld\n", d->size_data); - ntfs_log_quiet("Size init: %lld\n", d->size_init); - ntfs_log_quiet("Size vcn: %lld\n", d->size_vcn); - - ntfs_log_quiet("Data runs:\n"); - if ((!d->runlist) || (d->runlist[0].length <= 0)) { - ntfs_log_quiet(" None\n"); - } else { - for (i = 0; d->runlist[i].length > 0; i++) { - ntfs_log_quiet(" %lld @ %lld\n", - (long long)d->runlist[i].length, - (long long)d->runlist[i].lcn); - } - } - - ntfs_log_quiet("Amount potentially recoverable %d%%\n", - d->percent); - } - - ntfs_log_quiet("________________________________________\n\n"); -} - -/** - * list_record - Print a one line summary of the file - * @file: The file to work with - * - * Print a one line description of a file. - * - * Inode Flags %age Date Size Filename - * - * The output will contain the file's inode number (MFT Record), some flags, - * the percentage of the file that is recoverable, the last modification date, - * the size and the filename. - * - * The flags are F/D = File/Directory, N/R = Data is (Non-)Resident, - * C = Compressed, E = Encrypted, ! = Metadata may span multiple records. - * - * N.B. The file size is stored in many forms in several attributes. This - * display the largest it finds. - * - * N.B. If the filename is missing, or couldn't be converted to the current - * locale, "<none>" will be displayed. - * - * Return: none - */ -static void list_record(struct ufile *file) -{ - char buffer[20]; - struct list_head *item; - const char *name = NULL; - long long size = 0; - int percent = 0; - - char flagd = '.', flagr = '.', flagc = '.', flagx = '.'; - - strftime(buffer, sizeof(buffer), "%F", localtime(&file->date)); - - if (file->attr_list) - flagx = '!'; - - if (file->directory) - flagd = 'D'; - else - flagd = 'F'; - - list_for_each(item, &file->data) { - struct data *d = list_entry(item, struct data, list); - - if (!d->name) { - if (d->resident) - flagr = 'R'; - else - flagr = 'N'; - if (d->compressed) - flagc = 'C'; - if (d->encrypted) - flagc = 'E'; - - percent = max(percent, d->percent); - } - - size = max(size, d->size_data); - size = max(size, d->size_init); - } - - if (file->pref_name) - name = file->pref_name; - else - name = NONE; - - ntfs_log_quiet("%-8lld %c%c%c%c %3d%% %s %9lld %s\n", - file->inode, flagd, flagr, flagc, flagx, - percent, buffer, size, name); - -} - -/** - * name_match - Does a file have a name matching a regex - * @re: The regular expression object - * @file: The file to be tested - * - * Iterate through the file's $FILENAME attributes and compare them against the - * regular expression, created with regcomp. - * - * Return: 1 There is a matching filename. - * 0 There is no match. - */ -static int name_match(regex_t *re, struct ufile *file) -{ - struct list_head *item; - int result; - - if (!re || !file) - return 0; - - list_for_each(item, &file->name) { - struct filename *f = list_entry(item, struct filename, list); - - if (!f->name) - continue; - result = regexec(re, f->name, 0, NULL, 0); - if (result < 0) { - ntfs_log_perror("Couldn't compare filename with regex"); - return 0; - } else if (result == REG_NOERROR) { - ntfs_log_debug("Found a matching filename.\n"); - return 1; - } - } - - ntfs_log_debug("Filename '%s' doesn't match regex.\n", file->pref_name); - return 0; -} - -/** - * write_data - Write out a block of data - * @fd: File descriptor to write to - * @buffer: Data to write - * @bufsize: Amount of data to write - * - * Write a block of data to a file descriptor. - * - * Return: -1 Error, something went wrong - * 0 Success, all the data was written - */ -static unsigned int write_data(int fd, const char *buffer, - unsigned int bufsize) -{ - ssize_t result1, result2; - - if (!buffer) { - errno = EINVAL; - return -1; - } - - result1 = write(fd, buffer, bufsize); - if ((result1 == (ssize_t) bufsize) || (result1 < 0)) - return result1; - - /* Try again with the rest of the buffer */ - buffer += result1; - bufsize -= result1; - - result2 = write(fd, buffer, bufsize); - if (result2 < 0) - return result1; - - return result1 + result2; -} - -/** - * create_pathname - Create a path/file from some components - * @dir: Directory in which to create the file (optional) - * @name: Filename to give the file (optional) - * @stream: Name of the stream (optional) - * @buffer: Store the result here - * @bufsize: Size of buffer - * - * Create a filename from various pieces. The output will be of the form: - * dir/file - * dir/file:stream - * file - * file:stream - * - * All the components are optional. If the name is missing, "unknown" will be - * used. If the directory is missing the file will be created in the current - * directory. If the stream name is present it will be appended to the - * filename, delimited by a colon. - * - * N.B. If the buffer isn't large enough the name will be truncated. - * - * Return: n Length of the allocated name - */ -static int create_pathname(const char *dir, const char *name, - const char *stream, char *buffer, int bufsize) -{ - if (!name) - name = UNKNOWN; - - if (dir) - if (stream) - snprintf(buffer, bufsize, "%s/%s:%s", dir, name, stream); - else - snprintf(buffer, bufsize, "%s/%s", dir, name); - else - if (stream) - snprintf(buffer, bufsize, "%s:%s", name, stream); - else - snprintf(buffer, bufsize, "%s", name); - - return strlen(buffer); -} - -/** - * open_file - Open a file to write to - * @pathname: Path, name and stream of the file to open - * - * Create a file and return the file descriptor. - * - * N.B. If option force is given and existing file will be overwritten. - * - * Return: -1 Error, failed to create the file - * n Success, this is the file descriptor - */ -static int open_file(const char *pathname) -{ - int flags; - - ntfs_log_verbose("Creating file: %s\n", pathname); - - if (opts.force) - flags = O_RDWR | O_CREAT | O_TRUNC; - else - flags = O_RDWR | O_CREAT | O_EXCL; - - return open(pathname, flags, S_IRUSR | S_IWUSR); -} - -/** - * set_date - Set the file's date and time - * @pathname: Path and name of the file to alter - * @date: Date and time to set - * - * Give a file a particular date and time. - * - * Return: 1 Success, set the file's date and time - * 0 Error, failed to change the file's date and time - */ -static int set_date(const char *pathname, time_t date) -{ - struct utimbuf ut; - - if (!pathname) - return 0; - - ut.actime = date; - ut.modtime = date; - if (utime(pathname, &ut)) { - ntfs_log_error("ERROR: Couldn't set the file's date and time\n"); - return 0; - } - return 1; -} - -/** - * undelete_file - Recover a deleted file from an NTFS volume - * @vol: An ntfs volume obtained from ntfs_mount - * @inode: MFT Record number to be recovered - * - * Read an MFT Record and try an recover any data associated with it. Some of - * the clusters may be in use; these will be filled with zeros or the fill byte - * supplied in the options. - * - * Each data stream will be recovered and saved to a file. The file's name will - * be the original filename and it will be written to the current directory. - * Any named data stream will be saved as filename:streamname. - * - * The output file's name and location can be altered by using the command line - * options. - * - * N.B. We cannot tell if someone has overwritten some of the data since the - * file was deleted. - * - * Return: 0 Error, something went wrong - * 1 Success, the data was recovered - */ -static int undelete_file(ntfs_volume *vol, long long inode) -{ - char pathname[256]; - char *buffer = NULL; - unsigned int bufsize; - struct ufile *file; - int i, j; - long long start, end; - runlist_element *rl; - struct list_head *item; - int fd = -1; - long long k; - int result = 0; - char *name; - long long cluster_count; /* I'll need this variable (see below). +mabs */ - - if (!vol) - return 0; - - /* try to get record */ - file = read_record(vol, inode); - if (!file || !file->mft) { - ntfs_log_error("Can't read info from mft record %lld.\n", inode); - return 0; - } - - /* if flag was not set, print file informations */ - if (avoid_duplicate_printing == 0) { - if (opts.verbose) { - dump_record(file); - } else { - list_record(file); - //ntfs_log_quiet("\n"); - } - } - - bufsize = vol->cluster_size; - buffer = malloc(bufsize); - if (!buffer) - goto free; - - /* calc_percentage() must be called before dump_record() or - * list_record(). Otherwise, when undeleting, a file will always be - * listed as 0% recoverable even if successfully undeleted. +mabs - */ - if (file->mft->flags & MFT_RECORD_IN_USE) { - ntfs_log_error("Record is in use by the mft\n"); - if (!opts.force) { - free(buffer); - free_file(file); - return 0; - } - ntfs_log_verbose("Forced to continue.\n"); - } - - if (calc_percentage(file, vol) == 0) { - ntfs_log_quiet("File has no recoverable data.\n"); - goto free; - } - - if (list_empty(&file->data)) { - ntfs_log_quiet("File has no data. There is nothing to recover.\n"); - goto free; - } - - list_for_each(item, &file->data) { - struct data *d = list_entry(item, struct data, list); - - if (opts.output) - name = opts.output; - else - name = file->pref_name; - - create_pathname(opts.dest, name, d->name, pathname, sizeof(pathname)); - if (d->resident) { - fd = open_file(pathname); - if (fd < 0) { - ntfs_log_perror("Couldn't create file"); - goto free; - } - - ntfs_log_verbose("File has resident data.\n"); - if (write_data(fd, d->data, d->size_data) < d->size_data) { - ntfs_log_perror("Write failed"); - close(fd); - goto free; - } - - if (close(fd) < 0) { - ntfs_log_perror("Close failed"); - } - fd = -1; - } else { - rl = d->runlist; - if (!rl) { - ntfs_log_verbose("File has no runlist, hence no data.\n"); - continue; - } - - if (rl[0].length <= 0) { - ntfs_log_verbose("File has an empty runlist, hence no data.\n"); - continue; - } - - fd = open_file(pathname); - if (fd < 0) { - ntfs_log_perror("Couldn't create output file"); - goto free; - } - - if (rl[0].lcn == LCN_RL_NOT_MAPPED) { /* extended mft record */ - ntfs_log_verbose("Missing segment at beginning, %lld " - "clusters.\n", - (long long)rl[0].length); - memset(buffer, opts.fillbyte, bufsize); - for (k = 0; k < rl[0].length * vol->cluster_size; k += bufsize) { - if (write_data(fd, buffer, bufsize) < bufsize) { - ntfs_log_perror("Write failed"); - close(fd); - goto free; - } - } - } - - cluster_count = 0LL; - for (i = 0; rl[i].length > 0; i++) { - - if (rl[i].lcn == LCN_RL_NOT_MAPPED) { - ntfs_log_verbose("Missing segment at end, " - "%lld clusters.\n", - (long long)rl[i].length); - memset(buffer, opts.fillbyte, bufsize); - for (k = 0; k < rl[k].length * vol->cluster_size; k += bufsize) { - if (write_data(fd, buffer, bufsize) < bufsize) { - ntfs_log_perror("Write failed"); - close(fd); - goto free; - } - cluster_count++; - } - continue; - } - - if (rl[i].lcn == LCN_HOLE) { - ntfs_log_verbose("File has a sparse section.\n"); - memset(buffer, 0, bufsize); - for (k = 0; k < rl[k].length * vol->cluster_size; k += bufsize) { - if (write_data(fd, buffer, bufsize) < bufsize) { - ntfs_log_perror("Write failed"); - close(fd); - goto free; - } - } - continue; - } - - start = rl[i].lcn; - end = rl[i].lcn + rl[i].length; - - for (j = start; j < end; j++) { - if (utils_cluster_in_use(vol, j) && !opts.optimistic) { - memset(buffer, opts.fillbyte, bufsize); - if (write_data(fd, buffer, bufsize) < bufsize) { - ntfs_log_perror("Write failed"); - close(fd); - goto free; - } - } else { - if (ntfs_cluster_read(vol, j, 1, buffer) < 1) { - ntfs_log_perror("Read failed"); - close(fd); - goto free; - } - if (write_data(fd, buffer, bufsize) < bufsize) { - ntfs_log_perror("Write failed"); - close(fd); - goto free; - } - cluster_count++; - } - } - } - ntfs_log_quiet("\n"); - - /* - * The following block of code implements the --truncate option. - * Its semantics are as follows: - * IF opts.truncate is set AND data stream currently being recovered is - * non-resident AND data stream has no holes (100% recoverability) AND - * 0 <= (data->size_alloc - data->size_data) <= vol->cluster_size AND - * cluster_count * vol->cluster_size == data->size_alloc THEN file - * currently being written is truncated to data->size_data bytes before - * it's closed. - * This multiple checks try to ensure that only files with consistent - * values of size/occupied clusters are eligible for truncation. Note - * that resident streams need not be truncated, since the original code - * already recovers their exact length. +mabs - */ - if (opts.truncate) { - if (d->percent == 100 && d->size_alloc >= d->size_data && - (d->size_alloc - d->size_data) <= (long long)vol->cluster_size && - cluster_count * (long long)vol->cluster_size == d->size_alloc) { - if (ftruncate(fd, (off_t)d->size_data)) - ntfs_log_perror("Truncation failed"); - } else ntfs_log_quiet("Truncation not performed because file has an " - "inconsistent $MFT record.\n"); - } - - if (close(fd) < 0) { - ntfs_log_perror("Close failed"); - } - fd = -1; - - } - set_date(pathname, file->date); - if (d->name) - ntfs_log_quiet("Undeleted '%s:%s' successfully.\n", file->pref_name, d->name); - else - ntfs_log_quiet("Undeleted '%s' successfully.\n", file->pref_name); - } - result = 1; -free: - if (buffer) - free(buffer); - free_file(file); - return result; -} - -/** - * scan_disk - Search an NTFS volume for files that could be undeleted - * @vol: An ntfs volume obtained from ntfs_mount - * - * Read through all the MFT entries looking for deleted files. For each one - * determine how much of the data lies in unused disk space. - * - * The list can be filtered by name, size and date, using command line options. - * - * Return: -1 Error, something went wrong - * n Success, the number of recoverable files - */ -static int scan_disk(ntfs_volume *vol) -{ - s64 nr_mft_records; - const int BUFSIZE = 8192; - char *buffer = NULL; - int results = 0; - ntfs_attr *attr; - long long size; - long long bmpsize; - int i, j, k, b; - int percent; - struct ufile *file; - regex_t re; - - if (!vol) - return -1; - - attr = ntfs_attr_open(vol->mft_ni, AT_BITMAP, AT_UNNAMED, 0); - if (!attr) { - ntfs_log_perror("ERROR: Couldn't open $MFT/$BITMAP"); - return -1; - } - bmpsize = attr->initialized_size; - - buffer = malloc(BUFSIZE); - if (!buffer) { - ntfs_log_error("ERROR: Couldn't allocate memory in scan_disk()\n"); - results = -1; - goto out; - } - - if (opts.match) { - int flags = REG_NOSUB; - - if (!opts.match_case) - flags |= REG_ICASE; - if (regcomp(&re, opts.match, flags)) { - ntfs_log_error("ERROR: Couldn't create a regex.\n"); - goto out; - } - } - - nr_mft_records = vol->mft_na->initialized_size >> - vol->mft_record_size_bits; - - ntfs_log_quiet("Inode Flags %%age Date Size Filename\n"); - ntfs_log_quiet("---------------------------------------------------------------\n"); - for (i = 0; i < bmpsize; i += BUFSIZE) { - long long read_count = min((bmpsize - i), BUFSIZE); - size = ntfs_attr_pread(attr, i, read_count, buffer); - if (size < 0) - break; - - for (j = 0; j < size; j++) { - b = buffer[j]; - for (k = 0; k < 8; k++, b>>=1) { - if (((i+j)*8+k) >= nr_mft_records) - goto done; - if (b & 1) - continue; - file = read_record(vol, (i+j)*8+k); - if (!file) { - ntfs_log_error("Couldn't read MFT Record %d.\n", (i+j)*8+k); - continue; - } - - if ((opts.since > 0) && (file->date <= opts.since)) - goto skip; - if (opts.match && !name_match(&re, file)) - goto skip; - if (opts.size_begin && (opts.size_begin > file->max_size)) - goto skip; - if (opts.size_end && (opts.size_end < file->max_size)) - goto skip; - - percent = calc_percentage(file, vol); - if ((opts.percent == -1) || (percent >= opts.percent)) { - if (opts.verbose) - dump_record(file); - else - list_record(file); - - /* Was -u specified with no inode - so undelete file by regex */ - if (opts.mode == MODE_UNDELETE) { - if (!undelete_file(vol, file->inode)) - ntfs_log_verbose("ERROR: Failed to undelete " - "inode %lli\n!", - file->inode); - ntfs_log_info("\n"); - } - } - if (((opts.percent == -1) && (percent > 0)) || - ((opts.percent > 0) && (percent >= opts.percent))) { - results++; - } -skip: - free_file(file); - } - } - } -done: - ntfs_log_quiet("\nFiles with potentially recoverable content: %d\n", - results); -out: - if (opts.match) - regfree(&re); - free(buffer); - if (attr) - ntfs_attr_close(attr); - return results; -} - -/** - * copy_mft - Write a range of MFT Records to a file - * @vol: An ntfs volume obtained from ntfs_mount - * @mft_begin: First MFT Record to save - * @mft_end: Last MFT Record to save - * - * Read a number of MFT Records and write them to a file. - * - * Return: 0 Success, all the records were written - * 1 Error, something went wrong - */ -static int copy_mft(ntfs_volume *vol, long long mft_begin, long long mft_end) -{ - s64 nr_mft_records; - char pathname[256]; - ntfs_attr *mft; - char *buffer; - const char *name; - long long i; - int result = 1; - int fd; - - if (!vol) - return 1; - - if (mft_end < mft_begin) { - ntfs_log_error("Range to copy is backwards.\n"); - return 1; - } - - buffer = malloc(vol->mft_record_size); - if (!buffer) { - ntfs_log_error("Couldn't allocate memory in copy_mft()\n"); - return 1; - } - - mft = ntfs_attr_open(vol->mft_ni, AT_DATA, AT_UNNAMED, 0); - if (!mft) { - ntfs_log_perror("Couldn't open $MFT/$DATA"); - goto free; - } - - name = opts.output; - if (!name) { - name = MFTFILE; - ntfs_log_debug("No output filename, defaulting to '%s'.\n", - name); - } - - create_pathname(opts.dest, name, NULL, pathname, sizeof(pathname)); - fd = open_file(pathname); - if (fd < 0) { - ntfs_log_perror("Couldn't open output file '%s'", name); - goto attr; - } - - nr_mft_records = vol->mft_na->initialized_size >> - vol->mft_record_size_bits; - - mft_end = min(mft_end, nr_mft_records - 1); - - ntfs_log_debug("MFT records:\n"); - ntfs_log_debug("\tTotal: %8lld\n", nr_mft_records); - ntfs_log_debug("\tBegin: %8lld\n", mft_begin); - ntfs_log_debug("\tEnd: %8lld\n", mft_end); - - for (i = mft_begin; i <= mft_end; i++) { - if (ntfs_attr_pread(mft, vol->mft_record_size * i, - vol->mft_record_size, buffer) < vol->mft_record_size) { - ntfs_log_perror("Couldn't read MFT Record %lld", i); - goto close; - } - - if (write_data(fd, buffer, vol->mft_record_size) < vol->mft_record_size) { - ntfs_log_perror("Write failed"); - goto close; - } - } - - ntfs_log_verbose("Read %lld MFT Records\n", mft_end - mft_begin + 1); - result = 0; -close: - close(fd); -attr: - ntfs_attr_close(mft); -free: - free(buffer); - return result; -} - -/** - * handle_undelete - * - * Handles the undelete - */ -static int handle_undelete(ntfs_volume *vol) -{ - int result = 1; - int i; - unsigned long long inode; - - /* Check whether (an) inode(s) was specified or at least a regex! */ - if (nr_entries == 0) { - if (with_regex == 0) { - ntfs_log_error("ERROR: NO inode(s) AND NO match-regex " - "specified!\n"); - } else { - avoid_duplicate_printing= 1; - result = !scan_disk(vol); - if (result) - ntfs_log_verbose("ERROR: Failed to scan device " - "'%s'.\n", opts.device); - } - } else { - /* Normal undelete by specifying inode(s) */ - ntfs_log_quiet("Inode Flags %%age Date Size Filename\n"); - ntfs_log_quiet("---------------------------------------------------------------\n"); - - /* loop all given inodes */ - for (i = 0; i < nr_entries; i++) { - for (inode = ranges[i].begin; inode <= ranges[i].end; inode ++) { - /* Now undelete file */ - result = !undelete_file(vol, inode); - if (result) - ntfs_log_verbose("ERROR: Failed to " - "undelete inode %lli\n!", inode); - } - } - } - return (result); -} - -/** - * main - Begin here - * - * Start from here. - * - * Return: 0 Success, the program worked - * 1 Error, something went wrong - */ -int main(int argc, char *argv[]) -{ - ntfs_volume *vol; - int result = 1; - - ntfs_log_set_handler(ntfs_log_handler_outerr); - - with_regex = 0; - avoid_duplicate_printing = 0; - - if (!parse_options(argc, argv)) - goto free; - - utils_set_locale(); - - vol = utils_mount_volume(opts.device, NTFS_MNT_RDONLY | - (opts.force ? NTFS_MNT_FORCE : 0)); - if (!vol) - return 1; - - /* handling of the different modes */ - switch (opts.mode) { - /* Scanning */ - case MODE_SCAN: - result = !scan_disk(vol); - if (result) - ntfs_log_verbose("ERROR: Failed to scan device '%s'.\n", - opts.device); - break; - - /* Undelete-handling */ - case MODE_UNDELETE: - result= handle_undelete(vol); - break; - - /* Handling of copy mft */ - case MODE_COPY: - result = !copy_mft(vol, opts.mft_begin, opts.mft_end); - if (result) - ntfs_log_verbose("ERROR: Failed to read MFT blocks " - "%lld-%lld.\n", opts.mft_begin, - min((vol->mft_na->initialized_size >> - vol->mft_record_size_bits) , opts.mft_end)); - break; - default: - ; /* Cannot happen */ - } - - ntfs_umount(vol, FALSE); -free: - if (opts.match) - free(opts.match); - - return result; -} - diff --git a/usr/src/cmd/ntfsprogs/ntfsundelete.h b/usr/src/cmd/ntfsprogs/ntfsundelete.h deleted file mode 100644 index 529587b73c..0000000000 --- a/usr/src/cmd/ntfsprogs/ntfsundelete.h +++ /dev/null @@ -1,111 +0,0 @@ -/* - * ntfsundelete - Part of the Linux-NTFS project. - * - * Copyright (c) 2002 Richard Russon - * Copyright (c) 2007 Yura Pakhuchiy - * - * This utility will recover deleted files from an NTFS volume. - * - * 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 Linux-NTFS - * 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 _NTFSUNDELETE_H_ -#define _NTFSUNDELETE_H_ - -#include "types.h" -#include "list.h" -#include "runlist.h" - -enum optmode { - MODE_NONE = 0, - MODE_SCAN, - MODE_UNDELETE, - MODE_COPY, - MODE_ERROR -}; - -struct options { - char *device; /* Device/File to work with */ - enum optmode mode; /* Scan / Undelete / Copy */ - int percent; /* Minimum recoverability */ - int uinode; /* Undelete this inode */ - char *dest; /* Save file to this directory */ - char *output; /* With this filename */ - char *match; /* Pattern for filename matching */ - int match_case; /* Case sensitive matching */ - int truncate; /* Truncate files to exact size. */ - int quiet; /* Less output */ - int verbose; /* Extra output */ - int force; /* Override common sense */ - int optimistic; /* Undelete in-use clusters as well */ - int parent; /* Show parent directory */ - time_t since; /* Since this time */ - s64 size_begin; /* Range for file size */ - s64 size_end; - s64 mft_begin; /* Range for mft copy */ - s64 mft_end; - char fillbyte; /* Use for unrecoverable sections */ -}; - -struct filename { - struct list_head list; /* Previous/Next links */ - ntfschar *uname; /* Filename in unicode */ - int uname_len; /* and its length */ - long long size_alloc; /* Allocated size (multiple of cluster size) */ - long long size_data; /* Actual size of data */ - FILE_ATTR_FLAGS flags; - time_t date_c; /* Time created */ - time_t date_a; /* altered */ - time_t date_m; /* mft record changed */ - time_t date_r; /* read */ - char *name; /* Filename in current locale */ - FILE_NAME_TYPE_FLAGS name_space; - leMFT_REF parent_mref; - char *parent_name; -}; - -struct data { - struct list_head list; /* Previous/Next links */ - char *name; /* Stream name in current locale */ - ntfschar *uname; /* Unicode stream name */ - int uname_len; /* and its length */ - int resident; /* Stream is resident */ - int compressed; /* Stream is compressed */ - int encrypted; /* Stream is encrypted */ - long long size_alloc; /* Allocated size (multiple of cluster size) */ - long long size_data; /* Actual size of data */ - long long size_init; /* Initialised size, may be less than data size */ - long long size_vcn; /* Highest VCN in the data runs */ - runlist_element *runlist; /* Decoded data runs */ - int percent; /* Amount potentially recoverable */ - void *data; /* If resident, a pointer to the data */ -}; - -struct ufile { - long long inode; /* MFT record number */ - time_t date; /* Last modification date/time */ - struct list_head name; /* A list of filenames */ - struct list_head data; /* A list of data streams */ - char *pref_name; /* Preferred filename */ - char *pref_pname; /* parent filename */ - long long max_size; /* Largest size we find */ - int attr_list; /* MFT record may be one of many */ - int directory; /* MFT record represents a directory */ - MFT_RECORD *mft; /* Raw MFT record */ -}; - -#endif /* _NTFSUNDELETE_H_ */ - diff --git a/usr/src/cmd/ntfsprogs/sd.c b/usr/src/cmd/ntfsprogs/sd.c deleted file mode 100644 index a43ebf9c99..0000000000 --- a/usr/src/cmd/ntfsprogs/sd.c +++ /dev/null @@ -1,600 +0,0 @@ -#include "compat.h" -#include "types.h" -#include "layout.h" -#include "sd.h" - -/** - * init_system_file_sd - - * - * NTFS 3.1 - System files security decriptors - * ===================================================== - * - * Create the security descriptor for system file number @sys_file_no and - * return a pointer to the descriptor. - * - * Note the root directory system file (".") is very different and handled by a - * different function. - * - * The sd is returned in *@sd_val and has length *@sd_val_len. - * - * Do NOT free *@sd_val as it is static memory. This also means that you can - * only use *@sd_val until the next call to this function. - */ -void init_system_file_sd(int sys_file_no, u8 **sd_val, int *sd_val_len) -{ - static u8 sd_array[0x68]; - SECURITY_DESCRIPTOR_RELATIVE *sd; - ACL *acl; - ACCESS_ALLOWED_ACE *aa_ace; - SID *sid; - - if (sys_file_no < 0) { - *sd_val = NULL; - *sd_val_len = 0; - return; - } - *sd_val = sd_array; - sd = (SECURITY_DESCRIPTOR_RELATIVE*)&sd_array; - sd->revision = 1; - sd->alignment = 0; - sd->control = SE_SELF_RELATIVE | SE_DACL_PRESENT; - *sd_val_len = 0x64; - sd->owner = const_cpu_to_le32(0x48); - sd->group = const_cpu_to_le32(0x54); - sd->sacl = const_cpu_to_le32(0); - sd->dacl = const_cpu_to_le32(0x14); - /* - * Now at offset 0x14, as specified in the security descriptor, we have - * the DACL. - */ - acl = (ACL*)((char*)sd + le32_to_cpu(sd->dacl)); - acl->revision = 2; - acl->alignment1 = 0; - acl->size = const_cpu_to_le16(0x34); - acl->ace_count = const_cpu_to_le16(2); - acl->alignment2 = const_cpu_to_le16(0); - /* - * Now at offset 0x1c, just after the DACL's ACL, we have the first - * ACE of the DACL. The type of the ACE is access allowed. - */ - aa_ace = (ACCESS_ALLOWED_ACE*)((char*)acl + sizeof(ACL)); - aa_ace->type = ACCESS_ALLOWED_ACE_TYPE; - aa_ace->flags = 0; - aa_ace->size = const_cpu_to_le16(0x14); - switch (sys_file_no) { - case FILE_AttrDef: - case FILE_Boot: - aa_ace->mask = SYNCHRONIZE | STANDARD_RIGHTS_READ | - FILE_READ_ATTRIBUTES | FILE_READ_EA | FILE_READ_DATA; - break; - default: - aa_ace->mask = SYNCHRONIZE | STANDARD_RIGHTS_WRITE | - FILE_WRITE_ATTRIBUTES | FILE_READ_ATTRIBUTES | - FILE_WRITE_EA | FILE_READ_EA | FILE_APPEND_DATA | - FILE_WRITE_DATA | FILE_READ_DATA; - break; - } - aa_ace->sid.revision = 1; - aa_ace->sid.sub_authority_count = 1; - aa_ace->sid.identifier_authority.value[0] = 0; - aa_ace->sid.identifier_authority.value[1] = 0; - aa_ace->sid.identifier_authority.value[2] = 0; - aa_ace->sid.identifier_authority.value[3] = 0; - aa_ace->sid.identifier_authority.value[4] = 0; - /* SECURITY_NT_SID_AUTHORITY (S-1-5) */ - aa_ace->sid.identifier_authority.value[5] = 5; - aa_ace->sid.sub_authority[0] = - const_cpu_to_le32(SECURITY_LOCAL_SYSTEM_RID); - /* - * Now at offset 0x30 within security descriptor, just after the first - * ACE of the DACL. All system files, except the root directory, have - * a second ACE. - */ - /* The second ACE of the DACL. Type is access allowed. */ - aa_ace = (ACCESS_ALLOWED_ACE*)((char*)aa_ace + - le16_to_cpu(aa_ace->size)); - aa_ace->type = ACCESS_ALLOWED_ACE_TYPE; - aa_ace->flags = 0; - aa_ace->size = const_cpu_to_le16(0x18); - /* Only $AttrDef and $Boot behave differently to everything else. */ - switch (sys_file_no) { - case FILE_AttrDef: - case FILE_Boot: - aa_ace->mask = SYNCHRONIZE | STANDARD_RIGHTS_READ | - FILE_READ_ATTRIBUTES | FILE_READ_EA | - FILE_READ_DATA; - break; - default: - aa_ace->mask = SYNCHRONIZE | STANDARD_RIGHTS_READ | - FILE_WRITE_ATTRIBUTES | - FILE_READ_ATTRIBUTES | FILE_WRITE_EA | - FILE_READ_EA | FILE_APPEND_DATA | - FILE_WRITE_DATA | FILE_READ_DATA; - break; - } - aa_ace->sid.revision = 1; - aa_ace->sid.sub_authority_count = 2; - /* SECURITY_NT_SID_AUTHORITY (S-1-5) */ - aa_ace->sid.identifier_authority.value[0] = 0; - aa_ace->sid.identifier_authority.value[1] = 0; - aa_ace->sid.identifier_authority.value[2] = 0; - aa_ace->sid.identifier_authority.value[3] = 0; - aa_ace->sid.identifier_authority.value[4] = 0; - aa_ace->sid.identifier_authority.value[5] = 5; - aa_ace->sid.sub_authority[0] = - const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID); - aa_ace->sid.sub_authority[1] = - const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS); - /* - * Now at offset 0x48 into the security descriptor, as specified in the - * security descriptor, we now have the owner SID. - */ - sid = (SID*)((char*)sd + le32_to_cpu(sd->owner)); - sid->revision = 1; - sid->sub_authority_count = 1; - /* SECURITY_NT_SID_AUTHORITY (S-1-5) */ - sid->identifier_authority.value[0] = 0; - sid->identifier_authority.value[1] = 0; - sid->identifier_authority.value[2] = 0; - sid->identifier_authority.value[3] = 0; - sid->identifier_authority.value[4] = 0; - sid->identifier_authority.value[5] = 5; - sid->sub_authority[0] = const_cpu_to_le32(SECURITY_LOCAL_SYSTEM_RID); - /* - * Now at offset 0x54 into the security descriptor, as specified in the - * security descriptor, we have the group SID. - */ - sid = (SID*)((char*)sd + le32_to_cpu(sd->group)); - sid->revision = 1; - sid->sub_authority_count = 2; - /* SECURITY_NT_SID_AUTHORITY (S-1-5) */ - sid->identifier_authority.value[0] = 0; - sid->identifier_authority.value[1] = 0; - sid->identifier_authority.value[2] = 0; - sid->identifier_authority.value[3] = 0; - sid->identifier_authority.value[4] = 0; - sid->identifier_authority.value[5] = 5; - sid->sub_authority[0] = const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID); - sid->sub_authority[1] = const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS); -} - -/** - * init_root_sd - - * - * Creates the security_descriptor for the root folder on ntfs 3.1 as created - * by Windows Vista (when the format is done from the disk management MMC - * snap-in, note this is different from the format done from the disk - * properties in Windows Explorer). - */ -void init_root_sd(u8 **sd_val, int *sd_val_len) -{ - SECURITY_DESCRIPTOR_RELATIVE *sd; - ACL *acl; - ACCESS_ALLOWED_ACE *ace; - SID *sid; - - static char sd_array[0x102c]; - *sd_val_len = 0x102c; - *sd_val = (u8*)&sd_array; - - //security descriptor relative - sd = (SECURITY_DESCRIPTOR_RELATIVE*)sd_array; - sd->revision = SECURITY_DESCRIPTOR_REVISION; - sd->alignment = 0; - sd->control = SE_SELF_RELATIVE | SE_DACL_PRESENT; - sd->owner = const_cpu_to_le32(0x1014); - sd->group = const_cpu_to_le32(0x1020); - sd->sacl = 0; - sd->dacl = const_cpu_to_le32(sizeof(SECURITY_DESCRIPTOR_RELATIVE)); - - //acl - acl = (ACL*)((u8*)sd + sizeof(SECURITY_DESCRIPTOR_RELATIVE)); - acl->revision = ACL_REVISION; - acl->alignment1 = 0; - acl->size = const_cpu_to_le16(0x1000); - acl->ace_count = const_cpu_to_le16(0x08); - acl->alignment2 = 0; - - //ace1 - ace = (ACCESS_ALLOWED_ACE*)((u8*)acl + sizeof(ACL)); - ace->type = ACCESS_ALLOWED_ACE_TYPE; - ace->flags = 0; - ace->size = const_cpu_to_le16(0x18); - ace->mask = STANDARD_RIGHTS_ALL | FILE_WRITE_ATTRIBUTES | - FILE_LIST_DIRECTORY | FILE_WRITE_DATA | - FILE_ADD_SUBDIRECTORY | FILE_READ_EA | FILE_WRITE_EA | - FILE_TRAVERSE | FILE_DELETE_CHILD | - FILE_READ_ATTRIBUTES; - ace->sid.revision = SID_REVISION; - ace->sid.sub_authority_count = 0x02; - /* SECURITY_NT_SID_AUTHORITY (S-1-5) */ - ace->sid.identifier_authority.value[0] = 0; - ace->sid.identifier_authority.value[1] = 0; - ace->sid.identifier_authority.value[2] = 0; - ace->sid.identifier_authority.value[3] = 0; - ace->sid.identifier_authority.value[4] = 0; - ace->sid.identifier_authority.value[5] = 5; - ace->sid.sub_authority[0] = - const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID); - ace->sid.sub_authority[1] = const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS); - - //ace2 - ace = (ACCESS_ALLOWED_ACE*)((u8*)ace + le16_to_cpu(ace->size)); - ace->type = ACCESS_ALLOWED_ACE_TYPE; - ace->flags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | - INHERIT_ONLY_ACE; - ace->size = const_cpu_to_le16(0x18); - ace->mask = GENERIC_ALL; - ace->sid.revision = SID_REVISION; - ace->sid.sub_authority_count = 0x02; - /* SECURITY_NT_SID_AUTHORITY (S-1-5) */ - ace->sid.identifier_authority.value[0] = 0; - ace->sid.identifier_authority.value[1] = 0; - ace->sid.identifier_authority.value[2] = 0; - ace->sid.identifier_authority.value[3] = 0; - ace->sid.identifier_authority.value[4] = 0; - ace->sid.identifier_authority.value[5] = 5; - ace->sid.sub_authority[0] = - const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID); - ace->sid.sub_authority[1] = const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS); - - //ace3 - ace = (ACCESS_ALLOWED_ACE*)((u8*)ace + le16_to_cpu(ace->size)); - ace->type = ACCESS_ALLOWED_ACE_TYPE; - ace->flags = 0; - ace->size = const_cpu_to_le16(0x14); - ace->mask = STANDARD_RIGHTS_ALL | FILE_WRITE_ATTRIBUTES | - FILE_LIST_DIRECTORY | FILE_WRITE_DATA | - FILE_ADD_SUBDIRECTORY | FILE_READ_EA | FILE_WRITE_EA | - FILE_TRAVERSE | FILE_DELETE_CHILD | - FILE_READ_ATTRIBUTES; - ace->sid.revision = SID_REVISION; - ace->sid.sub_authority_count = 0x01; - /* SECURITY_NT_SID_AUTHORITY (S-1-5) */ - ace->sid.identifier_authority.value[0] = 0; - ace->sid.identifier_authority.value[1] = 0; - ace->sid.identifier_authority.value[2] = 0; - ace->sid.identifier_authority.value[3] = 0; - ace->sid.identifier_authority.value[4] = 0; - ace->sid.identifier_authority.value[5] = 5; - ace->sid.sub_authority[0] = - const_cpu_to_le32(SECURITY_LOCAL_SYSTEM_RID); - - //ace4 - ace = (ACCESS_ALLOWED_ACE*)((u8*)ace + le16_to_cpu(ace->size)); - ace->type = ACCESS_ALLOWED_ACE_TYPE; - ace->flags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | - INHERIT_ONLY_ACE; - ace->size = const_cpu_to_le16(0x14); - ace->mask = GENERIC_ALL; - ace->sid.revision = SID_REVISION; - ace->sid.sub_authority_count = 0x01; - /* SECURITY_NT_SID_AUTHORITY (S-1-5) */ - ace->sid.identifier_authority.value[0] = 0; - ace->sid.identifier_authority.value[1] = 0; - ace->sid.identifier_authority.value[2] = 0; - ace->sid.identifier_authority.value[3] = 0; - ace->sid.identifier_authority.value[4] = 0; - ace->sid.identifier_authority.value[5] = 5; - ace->sid.sub_authority[0] = - const_cpu_to_le32(SECURITY_LOCAL_SYSTEM_RID); - - //ace5 - ace = (ACCESS_ALLOWED_ACE*)((char*)ace + le16_to_cpu(ace->size)); - ace->type = ACCESS_ALLOWED_ACE_TYPE; - ace->flags = 0; - ace->size = const_cpu_to_le16(0x14); - ace->mask = SYNCHRONIZE | READ_CONTROL | DELETE | - FILE_WRITE_ATTRIBUTES | FILE_READ_ATTRIBUTES | - FILE_TRAVERSE | FILE_WRITE_EA | FILE_READ_EA | - FILE_ADD_SUBDIRECTORY | FILE_ADD_FILE | - FILE_LIST_DIRECTORY; - ace->sid.revision = SID_REVISION; - ace->sid.sub_authority_count = 0x01; - /* SECURITY_NT_SID_AUTHORITY (S-1-5) */ - ace->sid.identifier_authority.value[0] = 0; - ace->sid.identifier_authority.value[1] = 0; - ace->sid.identifier_authority.value[2] = 0; - ace->sid.identifier_authority.value[3] = 0; - ace->sid.identifier_authority.value[4] = 0; - ace->sid.identifier_authority.value[5] = 5; - ace->sid.sub_authority[0] = - const_cpu_to_le32(SECURITY_AUTHENTICATED_USER_RID); - - //ace6 - ace = (ACCESS_ALLOWED_ACE*)((u8*)ace + le16_to_cpu(ace->size)); - ace->type = ACCESS_ALLOWED_ACE_TYPE; - ace->flags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | - INHERIT_ONLY_ACE; - ace->size = const_cpu_to_le16(0x14); - ace->mask = GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | DELETE; - ace->sid.revision = SID_REVISION; - ace->sid.sub_authority_count = 0x01; - /* SECURITY_NT_SID_AUTHORITY (S-1-5) */ - ace->sid.identifier_authority.value[0] = 0; - ace->sid.identifier_authority.value[1] = 0; - ace->sid.identifier_authority.value[2] = 0; - ace->sid.identifier_authority.value[3] = 0; - ace->sid.identifier_authority.value[4] = 0; - ace->sid.identifier_authority.value[5] = 5; - ace->sid.sub_authority[0] = - const_cpu_to_le32(SECURITY_AUTHENTICATED_USER_RID); - - //ace7 - ace = (ACCESS_ALLOWED_ACE*)((u8*)ace + le16_to_cpu(ace->size)); - ace->type = ACCESS_ALLOWED_ACE_TYPE; - ace->flags = 0; - ace->size = const_cpu_to_le16(0x18); - ace->mask = SYNCHRONIZE | READ_CONTROL | FILE_READ_ATTRIBUTES | - FILE_TRAVERSE | FILE_READ_EA | FILE_LIST_DIRECTORY; - ace->sid.revision = SID_REVISION; - ace->sid.sub_authority_count = 0x02; - /* SECURITY_NT_SID_AUTHORITY (S-1-5) */ - ace->sid.identifier_authority.value[0] = 0; - ace->sid.identifier_authority.value[1] = 0; - ace->sid.identifier_authority.value[2] = 0; - ace->sid.identifier_authority.value[3] = 0; - ace->sid.identifier_authority.value[4] = 0; - ace->sid.identifier_authority.value[5] = 5; - ace->sid.sub_authority[0] = - const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID); - ace->sid.sub_authority[1] = const_cpu_to_le32(DOMAIN_ALIAS_RID_USERS); - - //ace8 - ace = (ACCESS_ALLOWED_ACE*)((u8*)ace + le16_to_cpu(ace->size)); - ace->type = ACCESS_ALLOWED_ACE_TYPE; - ace->flags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | - INHERIT_ONLY_ACE; - ace->size = const_cpu_to_le16(0x18); - ace->mask = GENERIC_READ | GENERIC_EXECUTE; - ace->sid.revision = SID_REVISION; - ace->sid.sub_authority_count = 0x02; - /* SECURITY_NT_SID_AUTHORITY (S-1-5) */ - ace->sid.identifier_authority.value[0] = 0; - ace->sid.identifier_authority.value[1] = 0; - ace->sid.identifier_authority.value[2] = 0; - ace->sid.identifier_authority.value[3] = 0; - ace->sid.identifier_authority.value[4] = 0; - ace->sid.identifier_authority.value[5] = 5; - ace->sid.sub_authority[0] = - const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID); - ace->sid.sub_authority[1] = const_cpu_to_le32(DOMAIN_ALIAS_RID_USERS); - - //owner sid - sid = (SID*)((char*)sd + le32_to_cpu(sd->owner)); - sid->revision = 0x01; - sid->sub_authority_count = 0x01; - /* SECURITY_NT_SID_AUTHORITY (S-1-5) */ - sid->identifier_authority.value[0] = 0; - sid->identifier_authority.value[1] = 0; - sid->identifier_authority.value[2] = 0; - sid->identifier_authority.value[3] = 0; - sid->identifier_authority.value[4] = 0; - sid->identifier_authority.value[5] = 5; - sid->sub_authority[0] = const_cpu_to_le32(SECURITY_LOCAL_SYSTEM_RID); - - //group sid - sid = (SID*)((char*)sd + le32_to_cpu(sd->group)); - sid->revision = 0x01; - sid->sub_authority_count = 0x01; - /* SECURITY_NT_SID_AUTHORITY (S-1-5) */ - sid->identifier_authority.value[0] = 0; - sid->identifier_authority.value[1] = 0; - sid->identifier_authority.value[2] = 0; - sid->identifier_authority.value[3] = 0; - sid->identifier_authority.value[4] = 0; - sid->identifier_authority.value[5] = 5; - sid->sub_authority[0] = const_cpu_to_le32(SECURITY_LOCAL_SYSTEM_RID); -} - -/** - * init_secure_sds - - * - * NTFS 3.1 - System files security decriptors - * =========================================== - * Create the security descriptor entries in $SDS data stream like they - * are in a partition, newly formatted with windows 2003 - */ -void init_secure_sds(char *sd_val) -{ - SECURITY_DESCRIPTOR_HEADER *sds; - SECURITY_DESCRIPTOR_RELATIVE *sd; - ACL *acl; - ACCESS_ALLOWED_ACE *ace; - SID *sid; - -/* - * security descriptor #1 - */ - //header - sds = (SECURITY_DESCRIPTOR_HEADER*)((char*)sd_val); - sds->hash = const_cpu_to_le32(0xF80312F0); - sds->security_id = const_cpu_to_le32(0x0100); - sds->offset = const_cpu_to_le64(0x00); - sds->length = const_cpu_to_le32(0x7C); - //security descriptor relative - sd = (SECURITY_DESCRIPTOR_RELATIVE*)((char*)sds + - sizeof(SECURITY_DESCRIPTOR_HEADER)); - sd->revision = 0x01; - sd->alignment = 0x00; - sd->control = SE_SELF_RELATIVE | SE_DACL_PRESENT; - sd->owner = const_cpu_to_le32(0x48); - sd->group = const_cpu_to_le32(0x58); - sd->sacl = const_cpu_to_le32(0x00); - sd->dacl = const_cpu_to_le32(0x14); - - //acl - acl = (ACL*)((char*)sd + sizeof(SECURITY_DESCRIPTOR_RELATIVE)); - acl->revision = 0x02; - acl->alignment1 = 0x00; - acl->size = const_cpu_to_le16(0x34); - acl->ace_count = const_cpu_to_le16(0x02); - acl->alignment2 = 0x00; - - //ace1 - ace = (ACCESS_ALLOWED_ACE*)((char*)acl + sizeof(ACL)); - ace->type = 0x00; - ace->flags = 0x00; - ace->size = const_cpu_to_le16(0x14); - ace->mask = const_cpu_to_le32(0x120089); - ace->sid.revision = 0x01; - ace->sid.sub_authority_count = 0x01; - /* SECURITY_NT_SID_AUTHORITY (S-1-5) */ - ace->sid.identifier_authority.value[0] = 0; - ace->sid.identifier_authority.value[1] = 0; - ace->sid.identifier_authority.value[2] = 0; - ace->sid.identifier_authority.value[3] = 0; - ace->sid.identifier_authority.value[4] = 0; - ace->sid.identifier_authority.value[5] = 5; - ace->sid.sub_authority[0] = - const_cpu_to_le32(SECURITY_LOCAL_SYSTEM_RID); - //ace2 - ace = (ACCESS_ALLOWED_ACE*)((char*)ace + le16_to_cpu(ace->size)); - ace->type = 0x00; - ace->flags = 0x00; - ace->size = const_cpu_to_le16(0x18); - ace->mask = const_cpu_to_le32(0x120089); - ace->sid.revision = 0x01; - ace->sid.sub_authority_count = 0x02; - /* SECURITY_NT_SID_AUTHORITY (S-1-5) */ - ace->sid.identifier_authority.value[0] = 0; - ace->sid.identifier_authority.value[1] = 0; - ace->sid.identifier_authority.value[2] = 0; - ace->sid.identifier_authority.value[3] = 0; - ace->sid.identifier_authority.value[4] = 0; - ace->sid.identifier_authority.value[5] = 5; - ace->sid.sub_authority[0] = - const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID); - ace->sid.sub_authority[1] = - const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS); - - //owner sid - sid = (SID*)((char*)sd + le32_to_cpu(sd->owner)); - sid->revision = 0x01; - sid->sub_authority_count = 0x02; - /* SECURITY_NT_SID_AUTHORITY (S-1-5) */ - sid->identifier_authority.value[0] = 0; - sid->identifier_authority.value[1] = 0; - sid->identifier_authority.value[2] = 0; - sid->identifier_authority.value[3] = 0; - sid->identifier_authority.value[4] = 0; - sid->identifier_authority.value[5] = 5; - sid->sub_authority[0] = - const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID); - sid->sub_authority[1] = - const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS); - //group sid - sid = (SID*)((char*)sd + le32_to_cpu(sd->group)); - sid->revision = 0x01; - sid->sub_authority_count = 0x02; - /* SECURITY_NT_SID_AUTHORITY (S-1-5) */ - sid->identifier_authority.value[0] = 0; - sid->identifier_authority.value[1] = 0; - sid->identifier_authority.value[2] = 0; - sid->identifier_authority.value[3] = 0; - sid->identifier_authority.value[4] = 0; - sid->identifier_authority.value[5] = 5; - sid->sub_authority[0] = - const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID); - sid->sub_authority[1] = - const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS); -/* - * security descriptor #2 - */ - //header - sds = (SECURITY_DESCRIPTOR_HEADER*)((char*)sd_val + 0x80); - sds->hash = const_cpu_to_le32(0xB32451); - sds->security_id = const_cpu_to_le32(0x0101); - sds->offset = const_cpu_to_le64(0x80); - sds->length = const_cpu_to_le32(0x7C); - - //security descriptor relative - sd = (SECURITY_DESCRIPTOR_RELATIVE*)((char*)sds + - sizeof(SECURITY_DESCRIPTOR_HEADER)); - sd->revision = 0x01; - sd->alignment = 0x00; - sd->control = SE_SELF_RELATIVE | SE_DACL_PRESENT; - sd->owner = const_cpu_to_le32(0x48); - sd->group = const_cpu_to_le32(0x58); - sd->sacl = const_cpu_to_le32(0x00); - sd->dacl = const_cpu_to_le32(0x14); - - //acl - acl = (ACL*)((char*)sd + sizeof(SECURITY_DESCRIPTOR_RELATIVE)); - acl->revision = 0x02; - acl->alignment1 = 0x00; - acl->size = const_cpu_to_le16(0x34); - acl->ace_count = const_cpu_to_le16(0x02); - acl->alignment2 = 0x00; - - //ace1 - ace = (ACCESS_ALLOWED_ACE*)((char*)acl + sizeof(ACL)); - ace->type = 0x00; - ace->flags = 0x00; - ace->size = const_cpu_to_le16(0x14); - ace->mask = const_cpu_to_le32(0x12019F); - ace->sid.revision = 0x01; - ace->sid.sub_authority_count = 0x01; - /* SECURITY_NT_SID_AUTHORITY (S-1-5) */ - ace->sid.identifier_authority.value[0] = 0; - ace->sid.identifier_authority.value[1] = 0; - ace->sid.identifier_authority.value[2] = 0; - ace->sid.identifier_authority.value[3] = 0; - ace->sid.identifier_authority.value[4] = 0; - ace->sid.identifier_authority.value[5] = 5; - ace->sid.sub_authority[0] = - const_cpu_to_le32(SECURITY_LOCAL_SYSTEM_RID); - //ace2 - ace = (ACCESS_ALLOWED_ACE*)((char*)ace + le16_to_cpu(ace->size)); - ace->type = 0x00; - ace->flags = 0x00; - ace->size = const_cpu_to_le16(0x18); - ace->mask = const_cpu_to_le32(0x12019F); - ace->sid.revision = 0x01; - ace->sid.sub_authority_count = 0x02; - /* SECURITY_NT_SID_AUTHORITY (S-1-5) */ - ace->sid.identifier_authority.value[0] = 0; - ace->sid.identifier_authority.value[1] = 0; - ace->sid.identifier_authority.value[2] = 0; - ace->sid.identifier_authority.value[3] = 0; - ace->sid.identifier_authority.value[4] = 0; - ace->sid.identifier_authority.value[5] = 5; - ace->sid.sub_authority[0] = - const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID); - ace->sid.sub_authority[1] = - const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS); - - //owner sid - sid = (SID*)((char*)sd + le32_to_cpu(sd->owner)); - sid->revision = 0x01; - sid->sub_authority_count = 0x02; - /* SECURITY_NT_SID_AUTHORITY (S-1-5) */ - sid->identifier_authority.value[0] = 0; - sid->identifier_authority.value[1] = 0; - sid->identifier_authority.value[2] = 0; - sid->identifier_authority.value[3] = 0; - sid->identifier_authority.value[4] = 0; - sid->identifier_authority.value[5] = 5; - sid->sub_authority[0] = - const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID); - sid->sub_authority[1] = - const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS); - - //group sid - sid = (SID*)((char*)sd + le32_to_cpu(sd->group)); - sid->revision = 0x01; - sid->sub_authority_count = 0x02; - /* SECURITY_NT_SID_AUTHORITY (S-1-5) */ - sid->identifier_authority.value[0] = 0; - sid->identifier_authority.value[1] = 0; - sid->identifier_authority.value[2] = 0; - sid->identifier_authority.value[3] = 0; - sid->identifier_authority.value[4] = 0; - sid->identifier_authority.value[5] = 5; - sid->sub_authority[0] = - const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID); - sid->sub_authority[1] = - const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS); - - return; -} diff --git a/usr/src/cmd/ntfsprogs/sd.h b/usr/src/cmd/ntfsprogs/sd.h deleted file mode 100644 index 7ad3e6a79c..0000000000 --- a/usr/src/cmd/ntfsprogs/sd.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef _NTFS_SD_H_ -#define _NTFS_SD_H_ - -#include "types.h" - -void init_system_file_sd(int sys_file_no, u8 **sd_val, int *sd_val_len); -void init_root_sd(u8 **sd_val, int *sd_val_len); -void init_secure_sds(char *sd_val); - -#endif /* _NTFS_SD_H_ */ - diff --git a/usr/src/cmd/ntfsprogs/utils.c b/usr/src/cmd/ntfsprogs/utils.c deleted file mode 100644 index d35533de22..0000000000 --- a/usr/src/cmd/ntfsprogs/utils.c +++ /dev/null @@ -1,1057 +0,0 @@ -/** - * utils.c - Part of the Linux-NTFS project. - * - * Copyright (c) 2002-2005 Richard Russon - * Copyright (c) 2003-2006 Anton Altaparmakov - * Copyright (c) 2003 Lode Leroy - * Copyright (c) 2005-2007 Yura Pakhuchiy - * - * A set of shared functions for ntfs utilities - * - * 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 Linux-NTFS - * 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 <stdio.h> -#endif -#ifdef HAVE_STDARG_H -#include <stdarg.h> -#endif -#ifdef HAVE_ERRNO_H -#include <errno.h> -#endif -#ifdef HAVE_SYS_TYPES_H -#include <sys/types.h> -#endif -#ifdef HAVE_SYS_STAT_H -#include <sys/stat.h> -#endif -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif -#ifdef HAVE_STRING_H -#include <string.h> -#endif -#ifdef HAVE_LOCALE_H -#include <locale.h> -#endif -#ifdef HAVE_LIBINTL_H -#include <libintl.h> -#endif -#ifdef HAVE_STDLIB_H -#include <stdlib.h> -#endif -#ifdef HAVE_LIMITS_H -#include <limits.h> -#endif -#ifdef HAVE_CTYPE_H -#include <ctype.h> -#endif - -#include "compat.h" -#include "utils.h" -#include "types.h" -#include "volume.h" -#include "debug.h" -#include "dir.h" -#include "version.h" -#include "logging.h" - -const char *ntfs_bugs = "Developers' email address: "NTFS_DEV_LIST"\n"; -const char *ntfs_home = "Linux NTFS homepage: http://www.linux-ntfs.org\n"; -const char *ntfs_gpl = "This program is free software, released under the GNU " - "General Public License\nand you are welcome to redistribute it under " - "certain conditions. It comes with\nABSOLUTELY NO WARRANTY; for " - "details read the GNU General Public License to be\nfound in the file " - "\"COPYING\" distributed with this program, or online at:\n" - "http://www.gnu.org/copyleft/gpl.html\n"; - -static const char *invalid_ntfs_msg = -"The device '%s' doesn't have a valid NTFS.\n" -"Maybe you selected the wrong device? Or the whole disk instead of a\n" -"partition (e.g. /dev/hda, not /dev/hda1)? Or the other way around?\n"; - -static const char *corrupt_volume_msg = -"NTFS is inconsistent. Run chkdsk /f on Windows then reboot it TWICE!\n" -"The usage of the /f parameter is very IMPORTANT! No modification was\n" -"made to NTFS by this software.\n"; - -static const char *hibernated_volume_msg = -"The NTFS partition is hibernated. Please resume Windows and turned it \n" -"off properly, so mounting could be done safely.\n"; - -static const char *unclean_journal_msg = -"Access is denied because the NTFS journal file is unclean. Choices are:\n" -" A) Shutdown Windows properly.\n" -" B) Click the 'Safely Remove Hardware' icon in the Windows taskbar\n" -" notification area before disconnecting the device.\n" -" C) Use 'Eject' from Windows Explorer to safely remove the device.\n" -" D) If you ran chkdsk previously then boot Windows again which will\n" -" automatically initialize the journal.\n" -" E) Submit 'force' option (WARNING: This solution it not recommended).\n" -" F) ntfsmount: Mount the volume read-only by using the 'ro' mount option.\n"; - -static const char *opened_volume_msg = -"Access 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 *dirty_volume_msg = -"Volume is scheduled for check.\n" -"Please boot into Windows TWICE, or use the 'force' option.\n" -"NOTE: If you had not scheduled check and last time accessed this volume\n" -"using ntfsmount and shutdown system properly, then init scripts in your\n" -"distribution are broken. Please report to your distribution developers\n" -"(NOT to us!) that init scripts kill ntfsmount or mount.ntfs-fuse during\n" -"shutdown instead of proper umount.\n"; - -static const char *fakeraid_msg = -"You seem to have a SoftRAID/FakeRAID hardware and must use an activated,\n" -"different device under /dev/mapper, (e.g. /dev/mapper/nvidia_eahaabcc1)\n" -"to mount NTFS. Please see the 'dmraid' documentation for help.\n"; - -/** - * utils_set_locale - */ -int utils_set_locale(void) -{ - const char *locale; - - locale = setlocale(LC_ALL, ""); - if (!locale) { - locale = setlocale(LC_ALL, NULL); - ntfs_log_error("Failed to set locale, using default '%s'.\n", - locale); - return 1; - } else { - return 0; - } -} - -/** - * utils_valid_device - Perform some safety checks on the device, before start - * @name: Full pathname of the device/file to work with - * @force: Continue regardless of problems - * - * Check that the name refers to a device and that is isn't already mounted. - * These checks can be overridden by using the force option. - * - * Return: 1 Success, we can continue - * 0 Error, we cannot use this device - */ -int utils_valid_device(const char *name, int force) -{ - unsigned long mnt_flags = 0; - struct stat st; - -#ifdef __CYGWIN32__ - /* FIXME: This doesn't work for Cygwin, so just return success. */ - return 1; -#endif - if (!name) { - errno = EINVAL; - return 0; - } - - if (stat(name, &st) == -1) { - if (errno == ENOENT) - ntfs_log_error("The device %s doesn't exist\n", name); - else - ntfs_log_perror("Error getting information about %s", - name); - return 0; - } - - /* Make sure the file system is not mounted. */ - if (ntfs_check_if_mounted(name, &mnt_flags)) { - ntfs_log_perror("Failed to determine whether %s is mounted", - name); - if (!force) { - ntfs_log_error("Use the force option to ignore this " - "error.\n"); - return 0; - } - ntfs_log_warning("Forced to continue.\n"); - } else if (mnt_flags & NTFS_MF_MOUNTED) { - if (!force) { - ntfs_log_error("%s", opened_volume_msg); - ntfs_log_error("You can use force option to avoid this " - "check, but this is not recommended\n" - "and may lead to data corruption.\n"); - return 0; - } - ntfs_log_warning("Forced to continue.\n"); - } - - return 1; -} - -/** - * utils_mount_volume - Mount an NTFS volume - */ -ntfs_volume * utils_mount_volume(const char *device, ntfs_mount_flags flags) -{ - ntfs_volume *vol; - - if (!device) { - errno = EINVAL; - return NULL; - } - - if (!utils_valid_device(device, flags & NTFS_MNT_FORCE)) - return NULL; - - vol = ntfs_mount(device, flags); - if (!vol) { - ntfs_log_perror("Failed to mount '%s'", device); - if (errno == EINVAL) - ntfs_log_error(invalid_ntfs_msg, device); - else if (errno == EIO) - ntfs_log_error("%s", corrupt_volume_msg); - else if (errno == EPERM) - ntfs_log_error("%s", hibernated_volume_msg); - else if (errno == EOPNOTSUPP) - ntfs_log_error("%s", unclean_journal_msg); - else if (errno == EBUSY) - ntfs_log_error("%s", opened_volume_msg); - else if (errno == ENXIO) - ntfs_log_error("%s", fakeraid_msg); - return NULL; - } - - if (NVolWasDirty(vol)) { - if (!(flags & NTFS_MNT_FORCE)) { - ntfs_log_error("%s", dirty_volume_msg); - ntfs_umount(vol, FALSE); - return NULL; - } - ntfs_log_error("WARNING: Dirty volume mount was forced by the " - "'force' mount option.\n"); - } - return vol; -} - -/** - * utils_parse_size - Convert a string representing a size - * @value: String to be parsed - * @size: Parsed size - * @scale: Whether or not to allow a suffix to scale the value - * - * Read a string and convert it to a number. Strings may be suffixed to scale - * them. Any number without a suffix is assumed to be in bytes. - * - * Suffix Description Multiple - * [tT] Terabytes 10^12 - * [gG] Gigabytes 10^9 - * [mM] Megabytes 10^6 - * [kK] Kilobytes 10^3 - * - * Notes: - * Only the first character of the suffix is read. - * The multipliers are decimal thousands, not binary: 1000, not 1024. - * If parse_size fails, @size will not be changed - * - * Return: 1 Success - * 0 Error, the string was malformed - */ -int utils_parse_size(const char *value, s64 *size, BOOL scale) -{ - long long result; - char *suffix = NULL; - - if (!value || !size) { - errno = EINVAL; - return 0; - } - - ntfs_log_debug("Parsing size '%s'.\n", value); - - result = strtoll(value, &suffix, 0); - if (result < 0 || errno == ERANGE) { - ntfs_log_error("Invalid size '%s'.\n", value); - return 0; - } - - if (!suffix) { - ntfs_log_error("Internal error, strtoll didn't return a suffix.\n"); - return 0; - } - - if (scale) { - switch (suffix[0]) { - case 't': case 'T': result *= 1000; - case 'g': case 'G': result *= 1000; - case 'm': case 'M': result *= 1000; - case 'k': case 'K': result *= 1000; - case '-': case 0: - break; - default: - ntfs_log_error("Invalid size suffix '%s'. Use T, G, M, or K.\n", suffix); - return 0; - } - } else { - if ((suffix[0] != '-') && (suffix[0] != 0)) { - ntfs_log_error("Invalid number '%.*s'.\n", (int)(suffix - value + 1), value); - return 0; - } - } - - ntfs_log_debug("Parsed size = %lld.\n", result); - *size = result; - return 1; -} - -/** - * utils_parse_range - Convert a string representing a range of numbers - * @string: The string to be parsed - * @start: The beginning of the range will be stored here - * @finish: The end of the range will be stored here - * - * Read a string of the form n-m. If the lower end is missing, zero will be - * substituted. If the upper end is missing LONG_MAX will be used. If the - * string cannot be parsed correctly, @start and @finish will not be changed. - * - * Return: 1 Success, a valid string was found - * 0 Error, the string was not a valid range - */ -int utils_parse_range(const char *string, s64 *start, s64 *finish, BOOL scale) -{ - s64 a, b; - char *middle; - - if (!string || !start || !finish) { - errno = EINVAL; - return 0; - } - - middle = strchr(string, '-'); - if (string == middle) { - ntfs_log_debug("Range has no beginning, defaulting to 0.\n"); - a = 0; - } else { - if (!utils_parse_size(string, &a, scale)) - return 0; - } - - if (middle) { - if (middle[1] == 0) { - b = LONG_MAX; // XXX ULLONG_MAX - ntfs_log_debug("Range has no end, defaulting to %lld.\n", b); - } else { - if (!utils_parse_size(middle+1, &b, scale)) - return 0; - } - } else { - b = a; - } - - ntfs_log_debug("Range '%s' = %lld - %lld\n", string, a, b); - - *start = a; - *finish = b; - return 1; -} - -/** - * find_attribute - Find an attribute of the given type - * @type: An attribute type, e.g. AT_FILE_NAME - * @ctx: A search context, created using ntfs_get_attr_search_ctx - * - * Using the search context to keep track, find the first/next occurrence of a - * given attribute type. - * - * N.B. This will return a pointer into @mft. As long as the search context - * has been created without an inode, it won't overflow the buffer. - * - * Return: Pointer Success, an attribute was found - * NULL Error, no matching attributes were found - */ -ATTR_RECORD * find_attribute(const ATTR_TYPES type, ntfs_attr_search_ctx *ctx) -{ - if (!ctx) { - errno = EINVAL; - return NULL; - } - - if (ntfs_attr_lookup(type, NULL, 0, 0, 0, NULL, 0, ctx) != 0) { - ntfs_log_debug("find_attribute didn't find an attribute of type: 0x%02x.\n", type); - return NULL; /* None / no more of that type */ - } - - ntfs_log_debug("find_attribute found an attribute of type: 0x%02x.\n", type); - return ctx->attr; -} - -/** - * find_first_attribute - Find the first attribute of a given type - * @type: An attribute type, e.g. AT_FILE_NAME - * @mft: A buffer containing a raw MFT record - * - * Search through a raw MFT record for an attribute of a given type. - * The return value is a pointer into the MFT record that was supplied. - * - * N.B. This will return a pointer into @mft. The pointer won't stray outside - * the buffer, since we created the search context without an inode. - * - * Return: Pointer Success, an attribute was found - * NULL Error, no matching attributes were found - */ -ATTR_RECORD * find_first_attribute(const ATTR_TYPES type, MFT_RECORD *mft) -{ - ntfs_attr_search_ctx *ctx; - ATTR_RECORD *rec; - - if (!mft) { - errno = EINVAL; - return NULL; - } - - ctx = ntfs_attr_get_search_ctx(NULL, mft); - if (!ctx) { - ntfs_log_error("Couldn't create a search context.\n"); - return NULL; - } - - rec = find_attribute(type, ctx); - ntfs_attr_put_search_ctx(ctx); - if (rec) - ntfs_log_debug("find_first_attribute: found attr of type 0x%02x.\n", type); - else - ntfs_log_debug("find_first_attribute: didn't find attr of type 0x%02x.\n", type); - return rec; -} - -/** - * utils_inode_get_name - * - * using inode - * get filename - * add name to list - * get parent - * if parent is 5 (/) stop - * get inode of parent - */ -#define max_path 20 -int utils_inode_get_name(ntfs_inode *inode, char *buffer, int bufsize) -{ - // XXX option: names = posix/win32 or dos - // flags: path, filename, or both - - - ntfs_volume *vol; - ntfs_attr_search_ctx *ctx; - ATTR_RECORD *rec; - FILE_NAME_ATTR *attr; - int name_space; - MFT_REF parent = FILE_root; - char *names[max_path + 1];// XXX ntfs_malloc? and make max bigger? - int i, len, offset = 0; - - if (!inode || !buffer) { - errno = EINVAL; - return 0; - } - - vol = inode->vol; - - //ntfs_log_debug("sizeof(char*) = %d, sizeof(names) = %d\n", sizeof(char*), sizeof(names)); - memset(names, 0, sizeof(names)); - - for (i = 0; i < max_path; i++) { - - ctx = ntfs_attr_get_search_ctx(inode, NULL); - if (!ctx) { - ntfs_log_error("Couldn't create a search context.\n"); - return 0; - } - - //ntfs_log_debug("i = %d, inode = %p (%lld)\n", i, inode, inode->mft_no); - - name_space = 4; - while ((rec = find_attribute(AT_FILE_NAME, ctx))) { - /* We know this will always be resident. */ - attr = (FILE_NAME_ATTR *) ((char *) rec + le16_to_cpu(rec->u.res.value_offset)); - - if (attr->file_name_type > name_space) { //XXX find the ... - continue; - } - - name_space = attr->file_name_type; - parent = le64_to_cpu(attr->parent_directory); - - if (names[i]) { - free(names[i]); - names[i] = NULL; - } - - if (ntfs_ucstombs(attr->file_name, attr->file_name_length, - &names[i], 0) < 0) { - char *temp; - ntfs_log_error("Couldn't translate filename to current locale.\n"); - temp = ntfs_malloc(30); - if (!temp) - return 0; - snprintf(temp, 30, "<MFT%llu>", (unsigned - long long)inode->mft_no); - names[i] = temp; - } - - //ntfs_log_debug("names[%d] %s\n", i, names[i]); - //ntfs_log_debug("parent = %lld\n", MREF(parent)); - } - - ntfs_attr_put_search_ctx(ctx); - - if (i > 0) /* Don't close the original inode */ - ntfs_inode_close(inode); - - if (MREF(parent) == FILE_root) { /* The root directory, stop. */ - //ntfs_log_debug("inode 5\n"); - break; - } - - inode = ntfs_inode_open(vol, parent); - if (!inode) { - ntfs_log_error("Couldn't open inode %llu.\n", - (unsigned long long)MREF(parent)); - break; - } - } - - if (i >= max_path) { - /* If we get into an infinite loop, we'll end up here. */ - ntfs_log_error("The directory structure is too deep (over %d) nested directories.\n", max_path); - return 0; - } - - /* Assemble the names in the correct order. */ - for (i = max_path; i >= 0; i--) { - if (!names[i]) - continue; - - len = snprintf(buffer + offset, bufsize - offset, "%c%s", PATH_SEP, names[i]); - if (len >= (bufsize - offset)) { - ntfs_log_error("Pathname was truncated.\n"); - break; - } - - offset += len; - } - - /* Free all the allocated memory */ - for (i = 0; i < max_path; i++) - free(names[i]); - - ntfs_log_debug("Pathname: %s\n", buffer); - - return 1; -} -#undef max_path - -/** - * utils_attr_get_name - */ -int utils_attr_get_name(ntfs_volume *vol, ATTR_RECORD *attr, char *buffer, int bufsize) -{ - int len, namelen; - char *name; - ATTR_DEF *attrdef; - - // flags: attr, name, or both - if (!attr || !buffer) { - errno = EINVAL; - return 0; - } - - attrdef = ntfs_attr_find_in_attrdef(vol, attr->type); - if (attrdef) { - name = NULL; - namelen = ntfs_ucsnlen(attrdef->name, sizeof(attrdef->name)); - if (ntfs_ucstombs(attrdef->name, namelen, &name, 0) < 0) { - ntfs_log_error("Couldn't translate attribute type to " - "current locale.\n"); - // <UNKNOWN>? - return 0; - } - len = snprintf(buffer, bufsize, "%s", name); - } else { - ntfs_log_error("Unknown attribute type 0x%02x\n", attr->type); - len = snprintf(buffer, bufsize, "<UNKNOWN>"); - } - - if (len >= bufsize) { - ntfs_log_error("Attribute type was truncated.\n"); - return 0; - } - - if (!attr->name_length) { - return 0; - } - - buffer += len; - bufsize -= len; - - name = NULL; - namelen = attr->name_length; - if (ntfs_ucstombs((ntfschar *)((char *)attr + le16_to_cpu( - attr->name_offset)), namelen, &name, 0) < 0) { - ntfs_log_error("Couldn't translate attribute name to current " - "locale.\n"); - // <UNKNOWN>? - len = snprintf(buffer, bufsize, "<UNKNOWN>"); - return 0; - } - - len = snprintf(buffer, bufsize, "(%s)", name); - free(name); - - if (len >= bufsize) { - ntfs_log_error("Attribute name was truncated.\n"); - return 0; - } - - return 0; -} - -/** - * utils_cluster_in_use - Determine if a cluster is in use - * @vol: An ntfs volume obtained from ntfs_mount - * @lcn: The Logical Cluster Number to test - * - * The metadata file $Bitmap has one binary bit representing each cluster on - * disk. The bit will be set for each cluster that is in use. The function - * reads the relevant part of $Bitmap into a buffer and tests the bit. - * - * This function has a static buffer in which it caches a section of $Bitmap. - * If the lcn, being tested, lies outside the range, the buffer will be - * refreshed. @bmplcn stores offset to the first bit (in bits) stored in the - * buffer. - * - * NOTE: Be very carefull with shifts by 3 everywhere in this function. - * - * Return: 1 Cluster is in use - * 0 Cluster is free space - * -1 Error occurred - */ -int utils_cluster_in_use(ntfs_volume *vol, long long lcn) -{ - static unsigned char buffer[512]; - static long long bmplcn = -(sizeof(buffer) << 3); - int byte, bit; - ntfs_attr *attr; - - if (!vol) { - errno = EINVAL; - return -1; - } - - /* Does lcn lie in the section of $Bitmap we already have cached? */ - if ((lcn < bmplcn) || (lcn >= (bmplcn + (sizeof(buffer) << 3)))) { - ntfs_log_debug("Bit lies outside cache.\n"); - attr = ntfs_attr_open(vol->lcnbmp_ni, AT_DATA, AT_UNNAMED, 0); - if (!attr) { - ntfs_log_perror("Couldn't open $Bitmap"); - return -1; - } - - /* Mark the buffer as in use, in case the read is shorter. */ - memset(buffer, 0xFF, sizeof(buffer)); - bmplcn = lcn & (~((sizeof(buffer) << 3) - 1)); - - if (ntfs_attr_pread(attr, (bmplcn >> 3), sizeof(buffer), - buffer) < 0) { - ntfs_log_perror("Couldn't read $Bitmap"); - ntfs_attr_close(attr); - return -1; - } - - ntfs_log_debug("Reloaded bitmap buffer.\n"); - ntfs_attr_close(attr); - } - - bit = 1 << (lcn & 7); - byte = (lcn >> 3) & (sizeof(buffer) - 1); - ntfs_log_debug("cluster = %lld, bmplcn = %lld, byte = %d, bit = %d, " - "in use %d\n", lcn, bmplcn, byte, bit, buffer[byte] & - bit); - - return (buffer[byte] & bit); -} - -/** - * utils_mftrec_in_use - Determine if a MFT Record is in use - * @vol: An ntfs volume obtained from ntfs_mount - * @mref: MFT Reference (inode number) - * - * The metadata file $BITMAP has one binary bit representing each record in the - * MFT. The bit will be set for each record that is in use. The function - * reads the relevant part of $BITMAP into a buffer and tests the bit. - * - * This function has a static buffer in which it caches a section of $BITMAP. - * If the mref, being tested, lies outside the range, the buffer will be - * refreshed. - * - * Return: 1 MFT Record is in use - * 0 MFT Record is unused - * -1 Error occurred - */ -int utils_mftrec_in_use(ntfs_volume *vol, MFT_REF mref) -{ - static u8 buffer[512]; - static s64 bmpmref = -sizeof(buffer) - 1; /* Which bit of $BITMAP is in the buffer */ - int byte, bit; - - ntfs_log_trace("Entering.\n"); - - if (!vol) { - errno = EINVAL; - return -1; - } - - /* Does mref lie in the section of $Bitmap we already have cached? */ - if (((s64)MREF(mref) < bmpmref) || ((s64)MREF(mref) >= (bmpmref + - (sizeof(buffer) << 3)))) { - ntfs_log_debug("Bit lies outside cache.\n"); - - /* Mark the buffer as not in use, in case the read is shorter. */ - memset(buffer, 0, sizeof(buffer)); - bmpmref = mref & (~((sizeof(buffer) << 3) - 1)); - - if (ntfs_attr_pread(vol->mftbmp_na, (bmpmref>>3), sizeof(buffer), buffer) < 0) { - ntfs_log_perror("Couldn't read $MFT/$BITMAP"); - return -1; - } - - ntfs_log_debug("Reloaded bitmap buffer.\n"); - } - - bit = 1 << (mref & 7); - byte = (mref >> 3) & (sizeof(buffer) - 1); - ntfs_log_debug("cluster = %lld, bmpmref = %lld, byte = %d, bit = %d, in use %d\n", mref, bmpmref, byte, bit, buffer[byte] & bit); - - return (buffer[byte] & bit); -} - -/** - * __metadata - */ -static int __metadata(ntfs_volume *vol, u64 num) -{ - if (num <= FILE_UpCase) - return 1; - if (!vol) - return -1; - if ((vol->major_ver == 3) && (num == FILE_Extend)) - return 1; - - return 0; -} - -/** - * utils_is_metadata - Determine if an inode represents a metadata file - * @inode: An ntfs inode to be tested - * - * A handful of files in the volume contain filesystem data - metadata. - * They can be identified by their inode number (offset in MFT/$DATA) or by - * their parent. - * - * Return: 1 inode is a metadata file - * 0 inode is not a metadata file - * -1 Error occurred - */ -int utils_is_metadata(ntfs_inode *inode) -{ - ntfs_volume *vol; - ATTR_RECORD *rec; - FILE_NAME_ATTR *attr; - MFT_RECORD *file; - u64 num; - - if (!inode) { - errno = EINVAL; - return -1; - } - - vol = inode->vol; - if (!vol) - return -1; - - num = inode->mft_no; - if (__metadata(vol, num) == 1) - return 1; - - file = inode->mrec; - if (file && (file->base_mft_record != 0)) { - num = MREF_LE(file->base_mft_record); - if (__metadata(vol, num) == 1) - return 1; - } - file = inode->mrec; - - rec = find_first_attribute(AT_FILE_NAME, inode->mrec); - if (!rec) - return -1; - - /* We know this will always be resident. */ - attr = (FILE_NAME_ATTR *)((char *)rec + le16_to_cpu(rec->u.res.value_offset)); - - num = MREF_LE(attr->parent_directory); - if ((num != FILE_root) && (__metadata(vol, num) == 1)) - return 1; - - return 0; -} - -/** - * utils_dump_mem - Display a block of memory in hex and ascii - * @buf: Buffer to be displayed - * @start: Offset into @buf to start from - * @length: Number of bytes to display - * @flags: Options to change the style of the output - * - * Display a block of memory in a tradition hex-dump manner. - * Optionally the ascii part can be turned off. - * - * The flags, described fully in utils.h, default to 0 (DM_DEFAULTS). - * Examples are: DM_INDENT (indent the output by one tab); DM_RED (colour the - * output); DM_NO_ASCII (only print the hex values). - */ -void utils_dump_mem(void *buf, int start, int length, int flags) -{ - int off, i, s, e, col; - u8 *mem = buf; - - s = start & ~15; // round down - e = (start + length + 15) & ~15; // round up - - for (off = s; off < e; off += 16) { - col = 30; - if (flags & DM_RED) - col += 1; - if (flags & DM_GREEN) - col += 2; - if (flags & DM_BLUE) - col += 4; - if (flags & DM_INDENT) - ntfs_log_debug("\t"); - if (flags & DM_BOLD) - ntfs_log_debug("\e[01m"); - if (flags & (DM_RED | DM_BLUE | DM_GREEN | DM_BOLD)) - ntfs_log_debug("\e[%dm", col); - if (off == s) - ntfs_log_debug("%6.6x ", start); - else - ntfs_log_debug("%6.6x ", off); - - for (i = 0; i < 16; i++) { - if ((i == 8) && (!(flags & DM_NO_DIVIDER))) - ntfs_log_debug(" -"); - if (((off+i) >= start) && ((off+i) < (start+length))) - ntfs_log_debug(" %02X", mem[off+i]); - else - ntfs_log_debug(" "); - } - if (!(flags & DM_NO_ASCII)) { - ntfs_log_debug(" "); - for (i = 0; i < 16; i++) { - if (((off+i) < start) || ((off+i) >= (start+length))) - ntfs_log_debug(" "); - else if (isprint(mem[off + i])) - ntfs_log_debug("%c", mem[off + i]); - else - ntfs_log_debug("."); - } - } - if (flags & (DM_RED | DM_BLUE | DM_GREEN | DM_BOLD)) - ntfs_log_debug("\e[0m"); - ntfs_log_debug("\n"); - } -} - - -/** - * mft_get_search_ctx - */ -struct mft_search_ctx * mft_get_search_ctx(ntfs_volume *vol) -{ - struct mft_search_ctx *ctx; - - if (!vol) { - errno = EINVAL; - return NULL; - } - - ctx = calloc(1, sizeof *ctx); - - ctx->mft_num = -1; - ctx->vol = vol; - - return ctx; -} - -/** - * mft_put_search_ctx - */ -void mft_put_search_ctx(struct mft_search_ctx *ctx) -{ - if (!ctx) - return; - if (ctx->inode) - ntfs_inode_close(ctx->inode); - free(ctx); -} - -/** - * mft_next_record - */ -int mft_next_record(struct mft_search_ctx *ctx) -{ - s64 nr_mft_records; - ATTR_RECORD *attr10 = NULL; - ATTR_RECORD *attr20 = NULL; - ATTR_RECORD *attr80 = NULL; - ntfs_attr_search_ctx *attr_ctx; - - if (!ctx) { - errno = EINVAL; - return -1; - } - - if (ctx->inode) { - ntfs_inode_close(ctx->inode); - ctx->inode = NULL; - } - - nr_mft_records = ctx->vol->mft_na->initialized_size >> - ctx->vol->mft_record_size_bits; - - for (ctx->mft_num++; (s64)ctx->mft_num < nr_mft_records; ctx->mft_num++) { - int in_use; - - ctx->flags_match = 0; - in_use = utils_mftrec_in_use(ctx->vol, (MFT_REF) ctx->mft_num); - if (in_use == -1) { - ntfs_log_error("Error reading inode %llu. Aborting.\n", - (unsigned long long)ctx->mft_num); - return -1; - } - - if (in_use) { - ctx->flags_match |= FEMR_IN_USE; - - ctx->inode = ntfs_inode_open(ctx->vol, (MFT_REF) ctx->mft_num); - if (ctx->inode == NULL) { - ntfs_log_error("Error reading inode %llu.\n", (unsigned - long long) ctx->mft_num); - continue; - } - - attr10 = find_first_attribute(AT_STANDARD_INFORMATION, ctx->inode->mrec); - attr20 = find_first_attribute(AT_ATTRIBUTE_LIST, ctx->inode->mrec); - attr80 = find_first_attribute(AT_DATA, ctx->inode->mrec); - - if (attr10) - ctx->flags_match |= FEMR_BASE_RECORD; - else - ctx->flags_match |= FEMR_NOT_BASE_RECORD; - - if (attr20) - ctx->flags_match |= FEMR_BASE_RECORD; - - if (attr80) - ctx->flags_match |= FEMR_FILE; - - if (ctx->flags_search & FEMR_DIR) { - attr_ctx = ntfs_attr_get_search_ctx(ctx->inode, NULL); - if (attr_ctx) { - if (ntfs_attr_lookup(AT_INDEX_ROOT, NTFS_INDEX_I30, 4, 0, 0, NULL, 0, attr_ctx) == 0) - ctx->flags_match |= FEMR_DIR; - - ntfs_attr_put_search_ctx(attr_ctx); - } else { - ntfs_log_error("Couldn't create a search context.\n"); - return -1; - } - } - - switch (utils_is_metadata(ctx->inode)) { - case 1: ctx->flags_match |= FEMR_METADATA; break; - case 0: ctx->flags_match |= FEMR_NOT_METADATA; break; - default: - ctx->flags_match |= FEMR_NOT_METADATA; break; - //ntfs_log_error("Error reading inode %lld.\n", ctx->mft_num); - //return -1; - } - - } else { // !in_use - ntfs_attr *mft; - - ctx->flags_match |= FEMR_NOT_IN_USE; - - ctx->inode = calloc(1, sizeof(*ctx->inode)); - if (!ctx->inode) { - ntfs_log_error("Out of memory. Aborting.\n"); - return -1; - } - - ctx->inode->mft_no = ctx->mft_num; - ctx->inode->vol = ctx->vol; - ctx->inode->mrec = ntfs_malloc(ctx->vol->mft_record_size); - if (!ctx->inode->mrec) { - free(ctx->inode); // == ntfs_inode_close - return -1; - } - - mft = ntfs_attr_open(ctx->vol->mft_ni, AT_DATA, - AT_UNNAMED, 0); - if (!mft) { - ntfs_log_perror("Couldn't open $MFT/$DATA"); - // free / close - return -1; - } - - if (ntfs_attr_pread(mft, ctx->vol->mft_record_size * ctx->mft_num, ctx->vol->mft_record_size, ctx->inode->mrec) < ctx->vol->mft_record_size) { - ntfs_log_perror("Couldn't read MFT Record %llu", - (unsigned long long) ctx->mft_num); - // free / close - ntfs_attr_close(mft); - return -1; - } - - ntfs_attr_close(mft); - } - - if (ctx->flags_match & ctx->flags_search) { - break; - } - - if (ntfs_inode_close(ctx->inode)) { - ntfs_log_error("Error closing inode %llu.\n", - (unsigned long long)ctx->mft_num); - return -errno; - } - - ctx->inode = NULL; - } - - return (ctx->inode == NULL); -} - - diff --git a/usr/src/cmd/ntfsprogs/utils.h b/usr/src/cmd/ntfsprogs/utils.h deleted file mode 100644 index a38f43104d..0000000000 --- a/usr/src/cmd/ntfsprogs/utils.h +++ /dev/null @@ -1,100 +0,0 @@ -/* - * utils.h - Part of the Linux-NTFS project. - * - * Copyright (c) 2002-2005 Richard Russon - * Copyright (c) 2004 Anton Altaparmakov - * - * A set of shared functions for ntfs utilities - * - * 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 Linux-NTFS - * 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_UTILS_H_ -#define _NTFS_UTILS_H_ - -#include "config.h" - -#include "types.h" -#include "layout.h" -#include "volume.h" - -#ifdef HAVE_ERRNO_H -#include <errno.h> -#endif -#ifdef HAVE_STDARG_H -#include <stdarg.h> -#endif - -extern const char *ntfs_bugs; -extern const char *ntfs_home; -extern const char *ntfs_gpl; - -int utils_set_locale(void); -int utils_parse_size(const char *value, s64 *size, BOOL scale); -int utils_parse_range(const char *string, s64 *start, s64 *finish, BOOL scale); -int utils_inode_get_name(ntfs_inode *inode, char *buffer, int bufsize); -int utils_attr_get_name(ntfs_volume *vol, ATTR_RECORD *attr, char *buffer, int bufsize); -int utils_cluster_in_use(ntfs_volume *vol, long long lcn); -int utils_mftrec_in_use(ntfs_volume *vol, MFT_REF mref); -int utils_is_metadata(ntfs_inode *inode); -void utils_dump_mem(void *buf, int start, int length, int flags); - -ATTR_RECORD * find_attribute(const ATTR_TYPES type, ntfs_attr_search_ctx *ctx); -ATTR_RECORD * find_first_attribute(const ATTR_TYPES type, MFT_RECORD *mft); - -int utils_valid_device(const char *name, int force); -ntfs_volume * utils_mount_volume(const char *device, ntfs_mount_flags flags); - -/** - * defines... - * if *not in use* then the other flags are ignored? - */ -#define FEMR_IN_USE (1 << 0) -#define FEMR_NOT_IN_USE (1 << 1) -#define FEMR_FILE (1 << 2) // $DATA -#define FEMR_DIR (1 << 3) // $INDEX_ROOT, "$I30" -#define FEMR_METADATA (1 << 4) -#define FEMR_NOT_METADATA (1 << 5) -#define FEMR_BASE_RECORD (1 << 6) -#define FEMR_NOT_BASE_RECORD (1 << 7) -#define FEMR_ALL_RECORDS 0xFF - -/** - * struct mft_search_ctx - */ -struct mft_search_ctx { - int flags_search; - int flags_match; - ntfs_inode *inode; - ntfs_volume *vol; - u64 mft_num; -}; - -struct mft_search_ctx * mft_get_search_ctx(ntfs_volume *vol); -void mft_put_search_ctx(struct mft_search_ctx *ctx); -int mft_next_record(struct mft_search_ctx *ctx); - -// Flags for dump mem -#define DM_DEFAULTS 0 -#define DM_NO_ASCII (1 << 0) -#define DM_NO_DIVIDER (1 << 1) -#define DM_INDENT (1 << 2) -#define DM_RED (1 << 3) -#define DM_GREEN (1 << 4) -#define DM_BLUE (1 << 5) -#define DM_BOLD (1 << 6) - -#endif /* _NTFS_UTILS_H_ */ |