summaryrefslogtreecommitdiff
path: root/usr/src/cmd/ntfsprogs
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/cmd/ntfsprogs')
-rw-r--r--usr/src/cmd/ntfsprogs/COPYING340
-rw-r--r--usr/src/cmd/ntfsprogs/CREDITS40
-rw-r--r--usr/src/cmd/ntfsprogs/Makefile160
-rw-r--r--usr/src/cmd/ntfsprogs/README9
-rw-r--r--usr/src/cmd/ntfsprogs/THIRDPARTYLICENSE.descrip1
-rw-r--r--usr/src/cmd/ntfsprogs/attrdef.c168
-rw-r--r--usr/src/cmd/ntfsprogs/attrdef.h7
-rw-r--r--usr/src/cmd/ntfsprogs/boot.c268
-rw-r--r--usr/src/cmd/ntfsprogs/boot.h7
-rw-r--r--usr/src/cmd/ntfsprogs/cluster.c119
-rw-r--r--usr/src/cmd/ntfsprogs/cluster.h39
-rw-r--r--usr/src/cmd/ntfsprogs/mkntfs.c4748
-rw-r--r--usr/src/cmd/ntfsprogs/ntfscat.c441
-rw-r--r--usr/src/cmd/ntfsprogs/ntfscat.h46
-rw-r--r--usr/src/cmd/ntfsprogs/ntfsclone.c1926
-rw-r--r--usr/src/cmd/ntfsprogs/ntfscluster.c565
-rw-r--r--usr/src/cmd/ntfsprogs/ntfscluster.h63
-rw-r--r--usr/src/cmd/ntfsprogs/ntfscmp.c1005
-rw-r--r--usr/src/cmd/ntfsprogs/ntfscp.c584
-rw-r--r--usr/src/cmd/ntfsprogs/ntfsfix.c542
-rw-r--r--usr/src/cmd/ntfsprogs/ntfsinfo.c2305
-rw-r--r--usr/src/cmd/ntfsprogs/ntfslabel.c412
-rw-r--r--usr/src/cmd/ntfsprogs/ntfsls.c719
-rw-r--r--usr/src/cmd/ntfsprogs/ntfsresize.c2501
-rw-r--r--usr/src/cmd/ntfsprogs/ntfsundelete.c2199
-rw-r--r--usr/src/cmd/ntfsprogs/ntfsundelete.h111
-rw-r--r--usr/src/cmd/ntfsprogs/sd.c600
-rw-r--r--usr/src/cmd/ntfsprogs/sd.h11
-rw-r--r--usr/src/cmd/ntfsprogs/utils.c1057
-rw-r--r--usr/src/cmd/ntfsprogs/utils.h100
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 = &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 = &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_ */