summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnton Altaparmakov <aia21@cam.ac.uk>2002-03-07 20:18:14 +0000
committerAnton Altaparmakov <aia21@cam.ac.uk>2002-03-07 20:18:14 +0000
commit6c8b850912a3f7dfbf9ddb687beec6e8b4ff72cb (patch)
tree268679110320576913e9f9fbb66c049bcd5b5067
parentc39e9205e9c097cfa94117a2e452957d2ce03c9e (diff)
Remove all traces of the old ntfs driver.
-rw-r--r--Documentation/filesystems/ntfs.txt254
-rw-r--r--fs/Config.help29
-rw-r--r--fs/Config.in2
-rw-r--r--fs/Makefile1
-rw-r--r--fs/ntfs/Makefile11
-rw-r--r--fs/ntfs/attr.c872
-rw-r--r--fs/ntfs/attr.h38
-rw-r--r--fs/ntfs/dir.c1104
-rw-r--r--fs/ntfs/dir.h48
-rw-r--r--fs/ntfs/fs.c1233
-rw-r--r--fs/ntfs/inode.c2317
-rw-r--r--fs/ntfs/inode.h58
-rw-r--r--fs/ntfs/macros.h40
-rw-r--r--fs/ntfs/ntfsendian.h60
-rw-r--r--fs/ntfs/ntfstypes.h84
-rw-r--r--fs/ntfs/struct.h69
-rw-r--r--fs/ntfs/super.c1413
-rw-r--r--fs/ntfs/super.h32
-rw-r--r--fs/ntfs/support.c316
-rw-r--r--fs/ntfs/support.h59
-rw-r--r--fs/ntfs/sysctl.c55
-rw-r--r--fs/ntfs/sysctl.h17
-rw-r--r--fs/ntfs/unistr.c168
-rw-r--r--fs/ntfs/unistr.h44
-rw-r--r--fs/ntfs/util.c265
-rw-r--r--fs/ntfs/util.h56
-rw-r--r--include/linux/fs.h2
-rw-r--r--include/linux/ntfs_fs.h29
-rw-r--r--include/linux/ntfs_fs_i.h97
-rw-r--r--include/linux/ntfs_fs_sb.h61
30 files changed, 0 insertions, 8834 deletions
diff --git a/Documentation/filesystems/ntfs.txt b/Documentation/filesystems/ntfs.txt
deleted file mode 100644
index 0624f1dd2506..000000000000
--- a/Documentation/filesystems/ntfs.txt
+++ /dev/null
@@ -1,254 +0,0 @@
-NTFS Overview
-=============
-
-Legato Systems, Inc. (http://www.legato.com) have sponsored Anton Altaparmakov
-to develop NTFS on Linux since June 2001.
-
-To mount an NTFS volume, use the filesystem type 'ntfs'. The driver
-currently works only in read-only mode, with no fault-tolerance supported.
-
-If you enable the dangerous(!) write support, make sure you can recover
-from a complete loss of data. Also, download the Linux-NTFS project
-distribution from Sourceforge at http://sourceforge.net/projects/linux-ntfs/
-and always run the included ntfsfix utility after performing a write to an
-NTFS partition from Linux to fix some of the damage done by the Linux NTFS
-driver and to schedule an automatic chkdsk when Windows reboots. You should
-run ntfsfix _after_ unmounting the partition in Linux but _before_ rebooting
-into Windows. During the next reboot into Windows, chkdsk will be run
-automatically fixing the remaining damage. If no errors are found it is a
-good indication that the driver + ntfsfix together worked to full
-satisfaction. (-;
-
-Please note that the experimental write support is limited to Windows NT4 and
-earlier versions at the moment.
-
-If you think you have discovered a bug please have look at the "Known bugs"
-section below to see whether it isn't known already.
-
-For ftdisk support, limited success was reported with volume sets on top of
-the md driver, although mirror and stripe sets should work as well - if the
-md driver can be talked into using the same layout as Windows NT. However,
-using the md driver will fail if any of your NTFS partitions have an odd
-number of sectors.
-
-Supported mount options
-=======================
-
-iocharset=name Character set to use when returning file names.
- Unlike VFAT, NTFS suppresses names that contain
- unconvertible characters. Note that most character
- sets contain insufficient characters to represent all
- possible Unicode characters that can exist on NTFS. To
- be sure you are not missing any files, you are advised
- to use the iocharset=utf8 which should be capable of
- representing all Unicode characters.
-
-utf8=<bool> Use UTF-8 for converting file names. - It is preferable
- to use iocharset=utf8 instead, but if the utf8 NLS is
- not available, you can use this utf8 option, which
- enables the driver's builtin utf8 conversion functions.
-
-uid=
-gid=
-umask= These options work as documented in mount(8).
- By default, the files are owned by root and
- not readable by anyone else.
-
-posix=<bool> If enabled, the file system distinguishes between
- upper and lower case. The 8.3 alias names are presented
- as hard links instead of being suppressed.
-
-show_sys_files=<bool> If enabled, show all system files as normal files. Note
- that $MFT does not appear unless specifically
- requested. For example in bash, use: "ls -l \$MFT".
- Be careful not to write anything to them or you could
- crash the kernel and/or corrupt your file system!
-
-mft_zone_multiplier= Set the MFT zone multiplier for the volume (this
- setting is not persistent across mounts and can be
- changed from mount to mount but cannot be changed on
- remount). Values of 1 to 4 are allowed, 1 being the
- default. The MFT zone multiplier determines how much
- space is reserved for the MFT on the volume. If all
- other space is used up, then the MFT zone will be
- shrunk dynamically, so this has no impact on the
- amount of free space. However, it can have an impact
- on performance by affecting fragmentation of the MFT.
- In general use the default. If you have a lot of small
- files then use a higher value. The values have the
- following meaning:
- Value MFT zone size (% of volume size)
- 1 12.5%
- 2 25%
- 3 37.5%
- 4 50%
-
-Known bugs and (mis-)features
-=============================
-
-- Do not use the driver for writing as it corrupts the file system. If you do
- use it, get the Linux-NTFS tools and use the ntfsfix utility after
- dismounting a partition you wrote to.
-
-- Writing of extension records is not supported properly.
-
-Please send bug reports/comments/feed back/abuse to the Linux-NTFS development
-list at sourceforge: linux-ntfs-dev@lists.sourceforge.net
-
-ChangeLog
-=========
-
-NTFS 1.1.21:
- - Fixed bug with reading $MFT where we try to read higher mft records
- before having read the $DATA attribute of $MFT. (Note this is only a
- partial solution which will only work in the case that the attribute
- list is resident or non-resident but $DATA is in the first 1024
- bytes. But this should be enough in the majority of cases. I am not
- going to bother fixing the general case until someone finds this to
- be a problem for them, which I doubt very much will ever happen...)
- - Fixed bogus BUG() call in readdir().
-
-NTFS 1.1.20:
- - Fixed two bugs in ntfs_readwrite_attr(). Thanks to Jan Kara for
- spotting the out of bounds one.
- - Check return value of set_blocksize() in ntfs_read_super() and make
- use of get_hardsect_size() to determine the minimum block size.
- - Fix return values of ntfs_vcn_to_lcn(). This should stop
- peoples start of partition being overwritten at random.
-
-NTFS 1.1.19:
- - Fixed ntfs_getdir_unsorted(), ntfs_readdir() and ntfs_printcb() to
- cope with arbitrary cluster sizes. Very important for Win2k+. Also,
- make them detect directories which are too large and truncate the
- enumeration pretending end of directory was reached. Detect more
- error conditions and overflows. All this fixes the problem where the
- driver could end up in an infinite loop under certain circumstances.
- - Fixed potential memory leaks in Unicode conversion functions and
- setup correct NULL return values.
-
-NTFS 1.1.18:
-
- - Enhanced & bug fixed cluster deallocation (race fixes, etc.)
- - Complete rewrite of cluster allocation, now race free.
- - Fixed several bugs in the attribute modification codepaths.
- - Hopefully fixed bug where the first sectors of some people's
- partitions would be overwritten by the mft. And in general fixed up
- mft extension code a bit (still incomplete though).
- - Introduce splice_runlist() to allow generic splicing of two run
- lists into one.
- - MFT zone is now implemented. [Stage 2 of 3; only lack dynamic
- growing of mft zone but that is AFAIK not even done by Windows, and
- the overhead would be so large that it is probably not worth doing
- at all, so Stage 3 might never happen...]
- - Complete rewrite of $MFT extension and ntfs inode allocation code.
- - Made the NTFS driver initialization string show the compile options
- used (i.e. whether read-only or read-write, whether a module, and
- whether with debug support).
- - Modify ntfs_fill_mft_header() to set all fields and to accept more
- arguments.
- - Get rid of superfluous add_mft_header().
- - Get rid of some unused code.
- - Fixed several bugs in and generally cleaned up ntfs_readdir,
- ntfs_getdir_unsorted(), and ntfs_printcb. Now they spew out huge
- amounts of debug output if debugging is enabled. This will be
- removed once I know that this works for everyone.
- - ntfs_readdir now shows hidden files. The only files that are now
- hidden are the first 16 inodes (i.e. the hard coded system files),
- which is consistent with Windows NT4. Using the show_sys_files mount
- option, these files are then shown, too.
- - Fixed the displaying of the "." and ".." directories. We still cannot
- cope with more than 65536 files in a directory index block which is
- not a problem and we now cannot cope with more than 32766 directory
- index blocks which should not be a problem unless you have a
- directory with an insanely large number of files in it. The exact
- number depends on the length of the file names of the directory
- entries and on the size of the dircetory index blocks.
- - Fixed all problems with the last file in a directory (e.g. the last
- file should no longer disappear and tab completion should work). If
- there are still disappearing files or any other problems with the
- last file in a directory, please report them! Thanks.
- - Rewrote ntfs_extend_attr() to use the new cluster allocator and the
- freshly introduced splice_runlists() function. This simplified
- ntfs_extend_attr() a lot which in turn seems to have removed one or
- more bugs from it.
- - Probably other things I have forgotten... (-;
- - Removed dollar signs from the names in the system file enumeration.
- Apparently gcc doesn't support dollar signs on PPC architecture.
- (Andrzej Krzysztofowicz)
-
-NTFS 1.1.17:
-
- - Fixed system file handling. No longer need to use show_sys_files
- option for driver to work fine. System files are now always treated
- the same, but without the option, they are made invisible to
- directory listings. As a result system files can once again be opened
- even without the show_sys_files option. This is important for the
- statfs system call to work properly, for example.
- - Implemented MFT zone including mount parameter to tune it (just like
- in Windows via the registry, only we make it per mount rather than
- global for the whole driver, so we are better but we have no way of
- storing the value as we don't have a registry so either specify on
- each mount or put it in /etc/fstab). [Stage 1 of 3, mount parameter
- handling.]
- - Fixed fixup functions to handle corruption cases and to return error
- codes to the caller.
- - Made fixup functions apply hotfixes where sensible. [Stage 1 of 2+,
- in memory only.]
- - Fixed ommission of "NTFS: " string in ntfs_error() output.
- - Fixed stupid if statement bug in unistr.c. Thanks to Yann E. Morin
- for spotting it.
- - Get rid of all uses of max and min macros. This actually allowed for
- optimizing the code in several places so it was a Good Thing(TM).
- - Make ntfs use generic_file_open to enforce the O_LARGEFILE flag.
- - Detect encrypted files and refuse to access them (return EACCES
- error code to user space).
- - Fix handling of encrypted & compressed files so that an encrypted
- file no longer is considered to be compressed (this was causing
- kernel segmentation faults).
-
-NTFS 1.1.16:
-
- - Removed non-functional uni_xlate mount options.
- - Clarified the semantics of the utf8 and iocharset mount options.
- - Threw out the non-functional mount options for using hard coded
- character set conversion. Only kept utf8 one.
- - Fixed handling of mount options and proper handling of faulty mount
- options on remount.
- - Cleaned up character conversion which basically became simplified a
- lot due to the removal of the above mentioned mount options.
- - Made character conversion to be always consistent. Previously we
- could output to the VFS file names which we would then not accept
- back from the VFS so in effect we were generating ghost entries in
- the directory listings which could not be accessed by any means.
- - Simplified time conversion functions drastically without sacrificing
- accuracy. (-8
- - Fixed a use of a pointer before the check for the pointer being
- NULL, reported by the Stanford checker.
- - Fixed several missing error checks, reported by the Stanford
- checker and fixed by Rasmus Andersen.
-
-NTFS 1.1.15 (changes since kernel 2.4.4's NTFS driver):
-
- - New mount option show_sys_files=<bool> to show all system files as
- normal files.
- - Support for files and in general any attributes up to the full 2TiB
- size supported by the NTFS filesystem. Note we only support up to
- 32-bits worth of inodes/clusters at this point.
- - Support for more than 128kiB sized runlists (using vmalloc_32()
- instead of kmalloc()).
- - Fixed races in allocation of clusters and mft records.
- - Fixed major bugs in attribute handling / searching / collation.
- - Fixed major bugs in compressing a run list into a mapping pairs array.
- - Fixed major bugs in inode allocation. Especially file create and
- mkdir.
- - Fixed memory leaks.
- - Fixed major bug in inode layout assignment of sequence numbers.
- - Lots of other bug fixes I can't think of right now...
- - Fixed NULL bug found by the Stanford checker in ntfs_dupuni2map().
- - Convert large stack variable to dynamically allocated one in
- ntfs_get_free_cluster_count() (found by Stanford checker).
-
-Kernel 2.4.4:
-
- - Started ChangeLog.
-
diff --git a/fs/Config.help b/fs/Config.help
index 3581b6fa3896..930dfda728f6 100644
--- a/fs/Config.help
+++ b/fs/Config.help
@@ -576,35 +576,6 @@ CONFIG_HPFS_FS
say M here and read <file:Documentation/modules.txt>. If unsure,
say N.
-CONFIG_NTFS_FS
- NTFS is the file system of Microsoft Windows NT. Say Y if you want
- to get read access to files on NTFS partitions of your hard drive.
- The Linux NTFS driver supports most of the mount options of the VFAT
- driver, see <file:Documentation/filesystems/ntfs.txt>. Saying Y here
- will give you read-only access to NTFS partitions.
-
- This code is also available as a module ( = code which can be
- inserted in and removed from the running kernel whenever you want).
- The module will be called ntfs.o. If you want to compile it as a
- module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_NTFS_RW
- If you say Y here, you will (maybe) be able to write to NTFS file
- systems as well as read from them. The read-write support in NTFS
- is far from being complete and is not well tested. If you say Y
- here, back up your NTFS volume first, since it will probably get
- damaged. Also, download the Linux-NTFS project distribution from
- Sourceforge at <http://linux-ntfs.sf.net/> and always run the
- included ntfsfix utility after writing to an NTFS partition from
- Linux to fix some of the damage done by the driver. You should run
- ntfsfix _after_ unmounting the partition in Linux but _before_
- rebooting into Windows. When Windows next boots, chkdsk will be
- run automatically to fix the remaining damage.
- Please note that write support is limited to Windows NT4 and
- earlier versions.
-
- If unsure, say N.
-
CONFIG_SYSV_FS
SCO, Xenix and Coherent are commercial Unix systems for Intel
machines, and Version 7 was used on the DEC PDP-11. Saying Y
diff --git a/fs/Config.in b/fs/Config.in
index 4db680cd4812..9e5532941c74 100644
--- a/fs/Config.in
+++ b/fs/Config.in
@@ -61,8 +61,6 @@ dep_mbool ' JFS statistics' CONFIG_JFS_STATISTICS $CONFIG_JFS_FS
tristate 'Minix fs support' CONFIG_MINIX_FS
tristate 'FreeVxFS file system support (VERITAS VxFS(TM) compatible)' CONFIG_VXFS_FS
-tristate 'NTFS file system support (read only)' CONFIG_NTFS_FS
-dep_mbool ' NTFS write support (DANGEROUS)' CONFIG_NTFS_RW $CONFIG_NTFS_FS $CONFIG_EXPERIMENTAL
tristate 'OS/2 HPFS file system support' CONFIG_HPFS_FS
diff --git a/fs/Makefile b/fs/Makefile
index 560fa8b317ba..81613f927b2e 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -52,7 +52,6 @@ subdir-$(CONFIG_SYSV_FS) += sysv
subdir-$(CONFIG_SMB_FS) += smbfs
subdir-$(CONFIG_NCP_FS) += ncpfs
subdir-$(CONFIG_HPFS_FS) += hpfs
-subdir-$(CONFIG_NTFS_FS) += ntfs
subdir-$(CONFIG_UFS_FS) += ufs
subdir-$(CONFIG_EFS_FS) += efs
subdir-$(CONFIG_JFFS_FS) += jffs
diff --git a/fs/ntfs/Makefile b/fs/ntfs/Makefile
deleted file mode 100644
index d331eb6f9c55..000000000000
--- a/fs/ntfs/Makefile
+++ /dev/null
@@ -1,11 +0,0 @@
-# Rules for making the NTFS driver
-
-O_TARGET := ntfs.o
-
-obj-y := fs.o sysctl.o support.o util.o inode.o dir.o super.o attr.o unistr.o
-obj-m := $(O_TARGET)
-# New version format started 3 February 2001.
-EXTRA_CFLAGS = -DNTFS_VERSION=\"1.1.21\" #-DDEBUG
-
-include $(TOPDIR)/Rules.make
-
diff --git a/fs/ntfs/attr.c b/fs/ntfs/attr.c
deleted file mode 100644
index b64aee7e17ba..000000000000
--- a/fs/ntfs/attr.c
+++ /dev/null
@@ -1,872 +0,0 @@
-/*
- * attr.c
- *
- * Copyright (C) 1996-1999 Martin von Löwis
- * Copyright (C) 1996-1997 Régis Duchesne
- * Copyright (C) 1998 Joseph Malicki
- * Copyright (C) 1999 Steve Dodd
- * Copyright (C) 2001 Anton Altaparmakov (AIA)
- */
-
-#include "ntfstypes.h"
-#include "struct.h"
-#include "attr.h"
-
-#include <linux/errno.h>
-#include <linux/ntfs_fs.h>
-#include "macros.h"
-#include "support.h"
-#include "util.h"
-#include "super.h"
-#include "inode.h"
-#include "unistr.h"
-
-/**
- * ntfs_find_attr_in_mft_rec - find attribute in mft record
- * @vol: volume on which attr resides
- * @m: mft record to search
- * @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 if 1 or case sensitive if 0 (ignored if @name NULL)
- * @instance: instance number to find
- *
- * Only search the specified mft record and it ignores the presence of an
- * attribute list attribute (unless it is the one being searched for,
- * obviously, in which case it is returned).
- */
-ntfs_u8* ntfs_find_attr_in_mft_rec(ntfs_volume *vol, ntfs_u8 *m, __u32 type,
- wchar_t *name, __u32 name_len, int ic, __u16 instance)
-{
- ntfs_u8 *a;
-
- /* Iterate over attributes in mft record @m. */
- a = m + NTFS_GETU16(m + 20); /* attrs_offset */
- for (; a >= m && a <= m + vol->mft_record_size;
- a += NTFS_GETU32(a + 4 /* length */)) {
- /* We catch $END with this more general check, too... */
- if (NTFS_GETU32(a + 0 /* type */) > type)
- return NULL;
- if (!NTFS_GETU32(a + 4 /* length */))
- break;
- if (NTFS_GETU32(a + 0 /* type */) != type)
- continue;
- /* If @name is present, compare the two names. */
- if (name && !ntfs_are_names_equal(name, name_len, (wchar_t*)
- (a + NTFS_GETU16(a + 10 /* name_offset */)),
- a[9] /* name_length */, ic, vol->upcase,
- vol->upcase_length)) {
- register int rc;
-
- rc = ntfs_collate_names(vol->upcase, vol->upcase_length,
- name, name_len, (wchar_t*)(a +
- NTFS_GETU16(a + 10 /* name_offset */)),
- a[9] /* name_length */, 1, 1);
- /*
- * If @name collates before a->name, there is no
- * matching attribute.
- */
- if (rc == -1)
- return NULL;
- /* If the strings are not equal, continue search. */
- if (rc)
- continue;
- rc = ntfs_collate_names(vol->upcase, vol->upcase_length,
- name, name_len, (wchar_t*)(a +
- NTFS_GETU16(a + 10 /* name_offset */)),
- a[9] /* name_length */, 0, 1);
- if (rc == -1)
- return NULL;
- if (rc)
- continue;
- }
- /*
- * The names match or @name not present. Check instance number.
- * and if it matches we have found the attribute and are done.
- */
- if (instance != NTFS_GETU16(a + 14 /* instance */))
- continue;
- ntfs_debug(DEBUG_FILE3, "ntfs_find_attr_in_mft_record: found: "
- "attr type 0x%x, instance number = 0x%x.\n",
- NTFS_GETU32(a + 0), instance);
- return a;
- }
- ntfs_error("ntfs_find_attr_in_mft_record: mft record 0x%x is corrupt"
- ". Run chkdsk.\n", m);
- return NULL;
-}
-
-/* Look if an attribute already exists in the inode, and if not, create it. */
-int ntfs_new_attr(ntfs_inode *ino, int type, void *name, int namelen,
- void *value, int value_len, int *pos, int *found)
-{
- int do_insert = 0;
- int i, m;
- ntfs_attribute *a;
-
- for (i = 0; i < ino->attr_count; i++)
- {
- a = ino->attrs + i;
- if (a->type < type)
- continue;
- if (a->type > type) {
- do_insert = 1;
- break;
- }
- /* If @name is present, compare the two names. */
- if (namelen && !ntfs_are_names_equal((wchar_t*)name, namelen,
- a->name, a->namelen /* name_length */,
- 1 /* ignore case*/, ino->vol->upcase,
- ino->vol->upcase_length)) {
- register int rc;
-
- rc = ntfs_collate_names(ino->vol->upcase,
- ino->vol->upcase_length, a->name,
- a->namelen, (wchar_t*)name, namelen,
- 1 /* ignore case */, 1);
- if (rc == -1)
- continue;
- if (rc == 1) {
- do_insert = 1;
- break;
- }
- rc = ntfs_collate_names(ino->vol->upcase,
- ino->vol->upcase_length, a->name,
- a->namelen, (wchar_t*)name, namelen,
- 0 /* case sensitive */, 1);
- if (rc == -1)
- continue;
- if (rc == 1) {
- do_insert = 1;
- break;
- }
- }
- /* Names are equal or no name was asked for. */
- /* If a value was specified compare the values. */
- if (value_len && a->resident) {
- if (!a->resident) {
- ntfs_error("ntfs_new_attr: Value specified but "
- "attribute non-resident. Bug!\n");
- return -EINVAL;
- }
- m = value_len;
- if (m > a->size)
- m = a->size;
- m = memcmp(value, a->d.data, m);
- if (m > 0)
- continue;
- if (m < 0) {
- do_insert = 1;
- break;
- }
- /* Values match until min of value lengths. */
- if (value_len > a->size)
- continue;
- if (value_len < a->size) {
- do_insert = 1;
- break;
- }
- }
- /* Full match! */
- *found = 1;
- *pos = i;
- return 0;
- }
- /* Re-allocate space. */
- if (ino->attr_count % 8 == 0)
- {
- ntfs_attribute* new;
- new = (ntfs_attribute*)ntfs_malloc((ino->attr_count + 8) *
- sizeof(ntfs_attribute));
- if (!new)
- return -ENOMEM;
- if (ino->attrs) {
- ntfs_memcpy(new, ino->attrs, ino->attr_count *
- sizeof(ntfs_attribute));
- ntfs_free(ino->attrs);
- }
- ino->attrs = new;
- }
- if (do_insert)
- ntfs_memmove(ino->attrs + i + 1, ino->attrs + i,
- (ino->attr_count - i) * sizeof(ntfs_attribute));
- ino->attr_count++;
- ino->attrs[i].type = type;
- ino->attrs[i].namelen = namelen;
- ino->attrs[i].name = name;
- *pos = i;
- *found = 0;
- return 0;
-}
-
-int ntfs_make_attr_resident(ntfs_inode *ino, ntfs_attribute *attr)
-{
- __s64 size = attr->size;
- if (size > 0) {
- /* FIXME: read data, free clusters */
- return -EOPNOTSUPP;
- }
- attr->resident = 1;
- return 0;
-}
-
-/* Store in the inode readable information about a run. */
-int ntfs_insert_run(ntfs_attribute *attr, int cnum, ntfs_cluster_t cluster,
- int len)
-{
- /* (re-)allocate space if necessary. */
- if ((attr->d.r.len * sizeof(ntfs_runlist)) % PAGE_SIZE == 0) {
- ntfs_runlist* new;
- unsigned long new_size;
-
- ntfs_debug(DEBUG_MALLOC, "ntfs_insert_run: re-allocating "
- "space: old attr->d.r.len = 0x%x\n",
- attr->d.r.len);
- new_size = attr->d.r.len * sizeof(ntfs_runlist) + PAGE_SIZE;
- if ((new_size >> PAGE_SHIFT) > num_physpages) {
- ntfs_error("ntfs_insert_run: attempted to allocate "
- "more pages than num_physpages."
- "This might be a bug or a corrupt"
- "file system.\n");
- return -1;
- }
- new = ntfs_vmalloc(new_size);
- if (!new) {
- ntfs_error("ntfs_insert_run: ntfs_vmalloc(new_size = "
- "0x%x) failed\n", new_size);
- return -1;
- }
- if (attr->d.r.runlist) {
- ntfs_memcpy(new, attr->d.r.runlist, attr->d.r.len
- * sizeof(ntfs_runlist));
- ntfs_vfree(attr->d.r.runlist);
- }
- attr->d.r.runlist = new;
- }
- if (attr->d.r.len > cnum)
- ntfs_memmove(attr->d.r.runlist + cnum + 1,
- attr->d.r.runlist + cnum,
- (attr->d.r.len - cnum) * sizeof(ntfs_runlist));
- attr->d.r.runlist[cnum].lcn = cluster;
- attr->d.r.runlist[cnum].len = len;
- attr->d.r.len++;
- return 0;
-}
-
-/**
- * ntfs_extend_attr - extend allocated size of an attribute
- * @ino: ntfs inode containing the attribute to extend
- * @attr: attribute which to extend
- * @len: desired new length for @attr (_not_ the amount to extend by)
- *
- * Extends an attribute. Allocate clusters on the volume which @ino belongs to.
- * Extends the run list accordingly, preferably by extending the last run of
- * the existing run list, first.
- *
- * Only modifies attr->allocated, i.e. doesn't touch attr->size, nor
- * attr->initialized.
- */
-int ntfs_extend_attr(ntfs_inode *ino, ntfs_attribute *attr, const __s64 len)
-{
- int rlen, rl2_len, err = 0;
- ntfs_cluster_t cluster, clen;
- ntfs_runlist *rl, *rl2;
-
- if ((attr->flags & (ATTR_IS_COMPRESSED | ATTR_IS_ENCRYPTED)) ||
- ino->record_count > 1)
- return -EOPNOTSUPP;
- /*
- * FIXME: Don't make non-resident if the attribute type is not right.
- * For example cannot make index attribute non-resident! (AIA)
- */
- if (attr->resident) {
- err = ntfs_make_attr_nonresident(ino, attr);
- if (err)
- return err;
- }
- if (len <= attr->allocated)
- return 0; /* Truly stupid things do sometimes happen. */
- rl = attr->d.r.runlist;
- rlen = attr->d.r.len;
- if (rlen > 0)
- cluster = rl[rlen - 1].lcn + rl[rlen - 1].len;
- else
- /* No preference for allocation space. */
- cluster = (ntfs_cluster_t)-1;
- /*
- * Calculate the extra space we need, and round up to multiple of
- * cluster size to get number of new clusters needed.
- */
- clen = (len - attr->allocated + ino->vol->cluster_size - 1) >>
- ino->vol->cluster_size_bits;
- if (!clen)
- return 0;
- err = ntfs_allocate_clusters(ino->vol, &cluster, &clen, &rl2,
- &rl2_len, DATA_ZONE);
- if (err)
- return err;
- attr->allocated += (__s64)clen << ino->vol->cluster_size_bits;
- if (rlen > 0) {
- err = splice_runlists(&rl, &rlen, rl2, rl2_len);
- ntfs_vfree(rl2);
- if (err)
- return err;
- } else {
- if (rl)
- ntfs_vfree(rl);
- rl = rl2;
- rlen = rl2_len;
- }
- attr->d.r.runlist = rl;
- attr->d.r.len = rlen;
- return 0;
-}
-
-int ntfs_make_attr_nonresident(ntfs_inode *ino, ntfs_attribute *attr)
-{
- int error;
- ntfs_io io;
- void *data = attr->d.data;
- __s64 len = attr->size;
-
- attr->d.r.len = 0;
- attr->d.r.runlist = NULL;
- attr->resident = 0;
- /*
- * ->allocated is updated by ntfs_extend_attr(), while ->initialized
- * and ->size are updated by ntfs_readwrite_attr(). (AIA)
- */
- attr->allocated = attr->initialized = 0;
- error = ntfs_extend_attr(ino, attr, len);
- if (error)
- return error; /* FIXME: On error, restore old values. */
- io.fn_put = ntfs_put;
- io.fn_get = ntfs_get;
- io.param = data;
- io.size = len;
- io.do_read = 0;
- return ntfs_readwrite_attr(ino, attr, 0, &io);
-}
-
-int ntfs_attr_allnonresident(ntfs_inode *ino)
-{
- int i, error = 0;
- ntfs_volume *vol = ino->vol;
-
- for (i = 0; !error && i < ino->attr_count; i++)
- {
- if (ino->attrs[i].type != vol->at_security_descriptor &&
- ino->attrs[i].type != vol->at_data)
- continue;
- error = ntfs_make_attr_nonresident(ino, ino->attrs + i);
- }
- return error;
-}
-
-/*
- * Resize the attribute to a newsize. attr->allocated and attr->size are
- * updated, but attr->initialized is not changed unless it becomes bigger than
- * attr->size, in which case it is set to attr->size.
- */
-int ntfs_resize_attr(ntfs_inode *ino, ntfs_attribute *attr, __s64 newsize)
-{
- int error = 0;
- __s64 oldsize = attr->size;
- int clustersizebits = ino->vol->cluster_size_bits;
- int i, count, newcount;
- ntfs_runlist *rl, *rlt;
-
- if (newsize == oldsize)
- return 0;
- if (attr->flags & (ATTR_IS_COMPRESSED | ATTR_IS_ENCRYPTED))
- return -EOPNOTSUPP;
- if (attr->resident) {
- void *v;
- if (newsize > ino->vol->mft_record_size) {
- error = ntfs_make_attr_nonresident(ino, attr);
- if (error)
- return error;
- return ntfs_resize_attr(ino, attr, newsize);
- }
- v = attr->d.data;
- if (newsize) {
- __s64 minsize = newsize;
- attr->d.data = ntfs_malloc(newsize);
- if (!attr->d.data) {
- ntfs_free(v);
- return -ENOMEM;
- }
- if (newsize > oldsize) {
- minsize = oldsize;
- ntfs_bzero((char*)attr->d.data + oldsize,
- newsize - oldsize);
- }
- ntfs_memcpy((char*)attr->d.data, v, minsize);
- } else
- attr->d.data = 0;
- ntfs_free(v);
- attr->size = newsize;
- return 0;
- }
- /* Non-resident attribute. */
- rl = attr->d.r.runlist;
- if (newsize < oldsize) {
- int rl_size;
- /*
- * FIXME: We might be going awfully wrong for newsize = 0,
- * possibly even leaking memory really badly. But considering
- * in that case there is more breakage due to -EOPNOTSUPP stuff
- * further down the code path, who cares for the moment... (AIA)
- */
- for (i = 0, count = 0; i < attr->d.r.len; i++) {
- if ((__s64)(count + rl[i].len) << clustersizebits >
- newsize) {
- i++;
- break;
- }
- count += (int)rl[i].len;
- }
- newcount = count;
- /* Free unused clusters in current run, unless sparse. */
- if (rl[--i].lcn != (ntfs_cluster_t)-1) {
- ntfs_cluster_t rounded = newsize - ((__s64)count <<
- clustersizebits);
- rounded = (rounded + ino->vol->cluster_size - 1) >>
- clustersizebits;
- error = ntfs_deallocate_cluster_run(ino->vol,
- rl[i].lcn + rounded,
- rl[i].len - rounded);
- if (error)
- return error; /* FIXME: Incomplete operation. */
- rl[i].len = rounded;
- newcount = count + rounded;
- }
- /* Free all other runs. */
- i++;
- error = ntfs_deallocate_clusters(ino->vol, rl + i,
- attr->d.r.len - i);
- if (error)
- return error; /* FIXME: Incomplete operation. */
- /*
- * Free space for extra runs in memory if enough memory left
- * to do so. FIXME: Only do it if it would free memory. (AIA)
- */
- rl_size = ((i + 1) * sizeof(ntfs_runlist) + PAGE_SIZE - 1) &
- PAGE_MASK;
- if (rl_size < ((attr->d.r.len * sizeof(ntfs_runlist) +
- PAGE_SIZE - 1) & PAGE_MASK)) {
- rlt = ntfs_vmalloc(rl_size);
- if (rlt) {
- ntfs_memcpy(rlt, rl, i * sizeof(ntfs_runlist));
- ntfs_vfree(rl);
- attr->d.r.runlist = rl = rlt;
- }
- }
- rl[i].lcn = (ntfs_cluster_t)-1;
- rl[i].len = (ntfs_cluster_t)0;
- attr->d.r.len = i;
- } else {
- error = ntfs_extend_attr(ino, attr, newsize);
- if (error)
- return error; /* FIXME: Incomplete operation. */
- newcount = (newsize + ino->vol->cluster_size - 1) >>
- clustersizebits;
- }
- /* Fill in new sizes. */
- attr->allocated = (__s64)newcount << clustersizebits;
- attr->size = newsize;
- if (attr->initialized > newsize)
- attr->initialized = newsize;
- if (!newsize)
- error = ntfs_make_attr_resident(ino, attr);
- return error;
-}
-
-int ntfs_create_attr(ntfs_inode *ino, int anum, char *aname, void *data,
- int dsize, ntfs_attribute **rattr)
-{
- void *name;
- int namelen;
- int found, i;
- int error;
- ntfs_attribute *attr;
-
- if (dsize > ino->vol->mft_record_size)
- /* FIXME: Non-resident attributes. */
- return -EOPNOTSUPP;
- if (aname) {
- namelen = strlen(aname);
- name = ntfs_malloc(2 * namelen);
- if (!name)
- return -ENOMEM;
- ntfs_ascii2uni(name, aname, namelen);
- } else {
- name = 0;
- namelen = 0;
- }
- error = ntfs_new_attr(ino, anum, name, namelen, data, dsize, &i,
- &found);
- if (error || found) {
- ntfs_free(name);
- return error ? error : -EEXIST;
- }
- *rattr = attr = ino->attrs + i;
- /* Allocate a new number.
- * FIXME: Should this happen on inode writeback?
- * FIXME: Extension records not supported. */
- error = ntfs_allocate_attr_number(ino, &i);
- if (error)
- return error;
- attr->attrno = i;
- if (attr->attrno + 1 != NTFS_GETU16(ino->attr + 0x28))
- ntfs_error("UH OH! attr->attrno (%i) != NTFS_GETU16(ino->attr "
- "+ 0x28) (%i)\n", attr->attrno,
- NTFS_GETU16(ino->attr + 0x28));
- attr->resident = 1;
- attr->flags = 0;
- attr->cengine = 0;
- attr->size = attr->allocated = attr->initialized = dsize;
-
- /* FIXME: INDEXED information should come from $AttrDef
- * Currently, only file names are indexed. As of NTFS v3.0 (Win2k),
- * this is no longer true. Different attributes can be indexed now. */
- if (anum == ino->vol->at_file_name)
- attr->indexed = 1;
- else
- attr->indexed = 0;
- attr->d.data = ntfs_malloc(dsize);
- if (!attr->d.data)
- return -ENOMEM;
- ntfs_memcpy(attr->d.data, data, dsize);
- return 0;
-}
-
-/*
- * Non-resident attributes are stored in runs (intervals of clusters).
- *
- * This function stores in the inode readable information about a non-resident
- * attribute.
- */
-static int ntfs_process_runs(ntfs_inode *ino, ntfs_attribute* attr,
- unsigned char *data)
-{
- int startvcn, endvcn;
- int vcn, cnum;
- ntfs_cluster_t cluster;
- int len, ctype;
- int er = 0;
- startvcn = NTFS_GETS64(data + 0x10);
- endvcn = NTFS_GETS64(data + 0x18);
-
- /* Check whether this chunk really belongs to the end. Problem with
- * this: this functions can get called on the last extent first, before
- * it is called on the other extents in sequence. This happens when the
- * base mft record contains the last extent instead of the first one
- * and the first extent is stored, like any intermediate extents in
- * extension mft records. This would be difficult to allow the way the
- * runlist is stored in memory. Thus we fix elsewhere by causing the
- * attribute list attribute to be processed immediately when found. The
- * extents will then be processed starting with the first one. */
- for (cnum = 0, vcn = 0; cnum < attr->d.r.len; cnum++)
- vcn += attr->d.r.runlist[cnum].len;
- if (vcn != startvcn) {
- ntfs_debug(DEBUG_FILE3, "ntfs_process_runs: ino = 0x%x, "
- "attr->type = 0x%x, startvcn = 0x%x, endvcn = 0x%x, "
- "vcn = 0x%x, cnum = 0x%x\n", ino->i_number, attr->type,
- startvcn, endvcn, vcn, cnum);
- if (vcn < startvcn) {
- ntfs_error("Problem with runlist in extended record\n");
- return -1;
- }
- /* Tried to insert an already inserted runlist. */
- return 0;
- }
- if (!endvcn) {
- if (!startvcn) {
- /* Allocated length. */
- endvcn = NTFS_GETS64(data + 0x28) - 1;
- endvcn >>= ino->vol->cluster_size_bits;
- } else {
- /* This is an extent. Allocated length is not defined!
- * Extents must have an endvcn though so this is an
- * error. */
- ntfs_error("Corrupt attribute extent. (endvcn is "
- "missing)\n");
- return -1;
- }
- }
- data = data + NTFS_GETU16(data + 0x20);
- cnum = attr->d.r.len;
- cluster = 0;
- for (vcn = startvcn; vcn <= endvcn; vcn += len) {
- if (ntfs_decompress_run(&data, &len, &cluster, &ctype)) {
- ntfs_debug(DEBUG_FILE3, "ntfs_process_runs: "
- "ntfs_decompress_run failed. i_number = 0x%x\n",
- ino->i_number);
- return -1;
- }
- if (ctype)
- er = ntfs_insert_run(attr, cnum, -1, len);
- else
- er = ntfs_insert_run(attr, cnum, cluster, len);
- if (er)
- break;
- cnum++;
- }
- if (er)
- ntfs_error("ntfs_process_runs: ntfs_insert_run failed\n");
- ntfs_debug(DEBUG_FILE3, "ntfs_process_runs: startvcn = 0x%x, vcn = 0x%x"
- ", endvcn = 0x%x, cnum = %i\n", startvcn, vcn,
- endvcn, cnum);
- return er;
-}
-
-/* Insert the attribute starting at attr in the inode ino. */
-int ntfs_insert_attribute(ntfs_inode *ino, unsigned char *attrdata)
-{
- int i, found;
- int type;
- short int *name;
- int namelen;
- void *data;
- ntfs_attribute *attr;
- int error;
-
- type = NTFS_GETU32(attrdata);
- namelen = NTFS_GETU8(attrdata + 9);
- ntfs_debug(DEBUG_FILE3, "ntfs_insert_attribute: ino->i_number 0x%x, "
- "attr type 0x%x\n", ino->i_number, type);
- /* Read the attribute's name if it has one. */
- if (!namelen)
- name = 0;
- else {
- /* 1 Unicode character fits in 2 bytes. */
- name = ntfs_malloc(2 * namelen);
- if (!name)
- return -ENOMEM;
- ntfs_memcpy(name, attrdata + NTFS_GETU16(attrdata + 10),
- 2 * namelen);
- }
- /* If resident look for value, too. */
- if (NTFS_GETU8(attrdata + 8) == 0)
- error = ntfs_new_attr(ino, type, name, namelen,
- attrdata + NTFS_GETU16(attrdata + 0x14),
- NTFS_GETU16(attrdata + 0x10), &i, &found);
- else
- error = ntfs_new_attr(ino, type, name, namelen, NULL, 0, &i,
- &found);
- if (error) {
- ntfs_debug(DEBUG_FILE3, "ntfs_insert_attribute: ntfs_new_attr "
- "failed.\n");
- if (name)
- ntfs_free(name);
- return error;
- }
- if (found) {
- /* It's already there, if not resident just process the runs. */
- if (!ino->attrs[i].resident) {
- ntfs_debug(DEBUG_FILE3, "ntfs_insert_attribute:"
- " processing runs 1.\n");
- /* FIXME: Check error code! (AIA) */
- ntfs_process_runs(ino, ino->attrs + i, attrdata);
- }
- return 0;
- }
- attr = ino->attrs + i;
- attr->resident = NTFS_GETU8(attrdata + 8) == 0;
- attr->flags = *(__u16*)(attrdata + 0xC);
- attr->attrno = NTFS_GETU16(attrdata + 0xE);
-
- if (attr->resident) {
- attr->size = NTFS_GETU16(attrdata + 0x10);
- data = attrdata + NTFS_GETU16(attrdata + 0x14);
- attr->d.data = (void*)ntfs_malloc(attr->size);
- if (!attr->d.data)
- return -ENOMEM;
- ntfs_memcpy(attr->d.data, data, attr->size);
- attr->indexed = NTFS_GETU8(attrdata + 0x16);
- } else {
- attr->allocated = NTFS_GETS64(attrdata + 0x28);
- attr->size = NTFS_GETS64(attrdata + 0x30);
- attr->initialized = NTFS_GETS64(attrdata + 0x38);
- attr->cengine = NTFS_GETU16(attrdata + 0x22);
- if (attr->flags & ATTR_IS_COMPRESSED)
- attr->compsize = NTFS_GETS64(attrdata + 0x40);
- ntfs_debug(DEBUG_FILE3, "ntfs_insert_attribute: "
- "attr->allocated = 0x%Lx, attr->size = 0x%Lx, "
- "attr->initialized = 0x%Lx\n", attr->allocated,
- attr->size, attr->initialized);
- ino->attrs[i].d.r.runlist = 0;
- ino->attrs[i].d.r.len = 0;
- ntfs_debug(DEBUG_FILE3, "ntfs_insert_attribute: processing "
- "runs 2.\n");
- /* FIXME: Check error code! (AIA) */
- ntfs_process_runs(ino, attr, attrdata);
- }
- return 0;
-}
-
-int ntfs_read_zero(ntfs_io *dest, int size)
-{
- int i;
- char *sparse = ntfs_calloc(512);
- if (!sparse)
- return -ENOMEM;
- i = 512;
- while (size) {
- if (i > size)
- i = size;
- dest->fn_put(dest, sparse, i);
- size -= i;
- }
- ntfs_free(sparse);
- return 0;
-}
-
-/* Process compressed attributes. */
-int ntfs_read_compressed(ntfs_inode *ino, ntfs_attribute *attr, __s64 offset,
- ntfs_io *dest)
-{
- int error = 0;
- int clustersizebits;
- int s_vcn, rnum, vcn, got, l1;
- __s64 copied, len, chunk, offs1, l, chunk2;
- ntfs_cluster_t cluster, cl1;
- char *comp = 0, *comp1;
- char *decomp = 0;
- ntfs_io io;
- ntfs_runlist *rl;
-
- l = dest->size;
- clustersizebits = ino->vol->cluster_size_bits;
- /* Starting cluster of potential chunk. There are three situations:
- a) In a large uncompressible or sparse chunk, s_vcn is in the middle
- of a run.
- b) s_vcn is right on a run border.
- c) When several runs make a chunk, s_vcn is before the chunks. */
- s_vcn = offset >> clustersizebits;
- /* Round down to multiple of 16. */
- s_vcn &= ~15;
- rl = attr->d.r.runlist;
- for (rnum = vcn = 0; rnum < attr->d.r.len && vcn + rl->len <= s_vcn;
- rnum++, rl++)
- vcn += rl->len;
- if (rnum == attr->d.r.len) {
- /* Beyond end of file. */
- /* FIXME: Check allocated / initialized. */
- dest->size = 0;
- return 0;
- }
- io.do_read = 1;
- io.fn_put = ntfs_put;
- io.fn_get = 0;
- cluster = rl->lcn;
- len = rl->len;
- copied = 0;
- while (l) {
- chunk = 0;
- if (cluster == (ntfs_cluster_t)-1) {
- /* Sparse cluster. */
- __s64 ll;
-
- if ((len - (s_vcn - vcn)) & 15)
- ntfs_error("Unexpected sparse chunk size.");
- ll = ((__s64)(vcn + len) << clustersizebits) - offset;
- if (ll > l)
- ll = l;
- chunk = ll;
- error = ntfs_read_zero(dest, ll);
- if (error)
- goto out;
- } else if (dest->do_read) {
- if (!comp) {
- comp = ntfs_malloc(16 << clustersizebits);
- if (!comp) {
- error = -ENOMEM;
- goto out;
- }
- }
- got = 0;
- /* We might need to start in the middle of a run. */
- cl1 = cluster + s_vcn - vcn;
- comp1 = comp;
- do {
- int delta;
-
- io.param = comp1;
- delta = s_vcn - vcn;
- if (delta < 0)
- delta = 0;
- l1 = len - delta;
- if (l1 > 16 - got)
- l1 = 16 - got;
- io.size = (__s64)l1 << clustersizebits;
- error = ntfs_getput_clusters(ino->vol, cl1, 0,
- &io);
- if (error)
- goto out;
- if (l1 + delta == len) {
- rnum++;
- rl++;
- vcn += len;
- cluster = cl1 = rl->lcn;
- len = rl->len;
- }
- got += l1;
- comp1 += (__s64)l1 << clustersizebits;
- } while (cluster != (ntfs_cluster_t)-1 && got < 16);
- /* Until empty run. */
- chunk = 16 << clustersizebits;
- if (cluster != (ntfs_cluster_t)-1 || got == 16)
- /* Uncompressible */
- comp1 = comp;
- else {
- if (!decomp) {
- decomp = ntfs_malloc(16 <<
- clustersizebits);
- if (!decomp) {
- error = -ENOMEM;
- goto out;
- }
- }
- /* Make sure there are null bytes after the
- * last block. */
- *(ntfs_u32*)comp1 = 0;
- ntfs_decompress(decomp, comp, chunk);
- comp1 = decomp;
- }
- offs1 = offset - ((__s64)s_vcn << clustersizebits);
- chunk2 = (16 << clustersizebits) - offs1;
- if (chunk2 > l)
- chunk2 = l;
- if (chunk > chunk2)
- chunk = chunk2;
- dest->fn_put(dest, comp1 + offs1, chunk);
- }
- l -= chunk;
- copied += chunk;
- offset += chunk;
- s_vcn = (offset >> clustersizebits) & ~15;
- if (l && offset >= ((__s64)(vcn + len) << clustersizebits)) {
- rnum++;
- rl++;
- vcn += len;
- cluster = rl->lcn;
- len = rl->len;
- }
- }
-out:
- if (comp)
- ntfs_free(comp);
- if (decomp)
- ntfs_free(decomp);
- dest->size = copied;
- return error;
-}
-
-int ntfs_write_compressed(ntfs_inode *ino, ntfs_attribute *attr, __s64 offset,
- ntfs_io *dest)
-{
- return -EOPNOTSUPP;
-}
-
diff --git a/fs/ntfs/attr.h b/fs/ntfs/attr.h
deleted file mode 100644
index cb8d9fd08d96..000000000000
--- a/fs/ntfs/attr.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * attr.h - Header file for attr.c
- *
- * Copyright (C) 1997 Régis Duchesne
- * Copyright (c) 2001 Anton Altaparmakov (AIA)
- */
-#include <linux/nls.h>
-
-ntfs_u8* ntfs_find_attr_in_mft_rec(ntfs_volume *vol, ntfs_u8 *m, __u32 type,
- wchar_t *name, __u32 name_len, int ic, __u16 instance);
-
-int ntfs_extend_attr(ntfs_inode *ino, ntfs_attribute *attr, const __s64 len);
-
-int ntfs_resize_attr(ntfs_inode *ino, ntfs_attribute *attr, __s64 newsize);
-
-int ntfs_insert_attribute(ntfs_inode *ino, unsigned char* attrdata);
-
-int ntfs_read_compressed(ntfs_inode *ino, ntfs_attribute *attr, __s64 offset,
- ntfs_io *dest);
-
-int ntfs_write_compressed(ntfs_inode *ino, ntfs_attribute *attr, __s64 offset,
- ntfs_io *dest);
-
-int ntfs_create_attr(ntfs_inode *ino, int anum, char *aname, void *data,
- int dsize, ntfs_attribute **rattr);
-
-int ntfs_read_zero(ntfs_io *dest, int size);
-
-int ntfs_make_attr_nonresident(ntfs_inode *ino, ntfs_attribute *attr);
-
-int ntfs_attr_allnonresident(ntfs_inode *ino);
-
-int ntfs_new_attr(ntfs_inode *ino, int type, void *name, int namelen,
- void *value, int value_len, int *pos, int *found);
-
-int ntfs_insert_run(ntfs_attribute *attr, int cnum, ntfs_cluster_t cluster,
- int len);
-
diff --git a/fs/ntfs/dir.c b/fs/ntfs/dir.c
deleted file mode 100644
index eb201792526d..000000000000
--- a/fs/ntfs/dir.c
+++ /dev/null
@@ -1,1104 +0,0 @@
-/*
- * dir.c
- *
- * Copyright (C) 1995-1997, 1999 Martin von Löwis
- * Copyright (C) 1999 Steve Dodd
- * Copyright (C) 1999 Joseph Malicki
- * Copyright (C) 2001 Anton Altaparmakov (AIA)
- */
-
-#include "ntfstypes.h"
-#include "struct.h"
-#include "dir.h"
-#include "macros.h"
-
-#include <linux/errno.h>
-#include "super.h"
-#include "inode.h"
-#include "attr.h"
-#include "support.h"
-#include "util.h"
-#include <linux/smp_lock.h>
-#include <linux/bitops.h>
-
-static char I30[] = "$I30";
-
-/* An index record should start with INDX, and the last word in each block
- * should contain the check value. If it passes, the original values need to
- * be restored. */
-int ntfs_check_index_record(ntfs_inode *ino, char *record)
-{
- return ntfs_fixup_record(record, "INDX", ino->u.index.recordsize);
-}
-
-static inline int ntfs_is_top(ntfs_u64 stack)
-{
- return stack == 14;
-}
-
-static int ntfs_pop(ntfs_u64 *stack)
-{
- static int width[16] = {1,2,1,3,1,2,1,4,1,2,1,3,1,2,1,-1};
- int res = -1;
-
- switch (width[*stack & 15]) {
- case 1:
- res = (int)((*stack & 15) >> 1);
- *stack >>= 4;
- break;
- case 2:
- res = (int)(((*stack & 63) >> 2) + 7);
- *stack >>= 6;
- break;
- case 3:
- res = (int)(((*stack & 255) >> 3) + 23);
- *stack >>= 8;
- break;
- case 4:
- res = (int)(((*stack & 1023) >> 4) + 55);
- *stack >>= 10;
- break;
- default:
- ntfs_error("Unknown encoding\n");
- }
- return res;
-}
-
-static inline unsigned int ntfs_top(void)
-{
- return 14;
-}
-
-static ntfs_u64 ntfs_push(ntfs_u64 stack, int i)
-{
- if (i < 7)
- return (stack << 4) | (i << 1);
- if (i < 23)
- return (stack << 6) | ((i - 7) << 2) | 1;
- if (i < 55)
- return (stack << 8) | ((i - 23) << 3) | 3;
- if (i < 120)
- return (stack << 10) | ((i - 55) << 4) | 7;
- ntfs_error("Too many entries\n");
- return ~((ntfs_u64)0);
-}
-
-#if 0
-static void ntfs_display_stack(ntfs_u64 stack)
-{
- while(!ntfs_is_top(stack))
- {
- printf("%d ", ntfs_pop(&stack));
- }
- printf("\n");
-}
-#endif
-
-/* True if the entry points to another block of entries. */
-static inline int ntfs_entry_has_subnodes(char *entry)
-{
- return (NTFS_GETU16(entry + 0xc) & 1);
-}
-
-/* True if it is not the 'end of dir' entry. */
-static inline int ntfs_entry_is_used(char *entry)
-{
- return !(NTFS_GETU16(entry + 0xc) & 2);
-}
-
-/*
- * Removed RACE for allocating index blocks. But stil not too happy.
- * There might be more races afterwards. (AIA)
- */
-static int ntfs_allocate_index_block(ntfs_iterate_s *walk)
-{
- ntfs_attribute *allocation, *bitmap = 0;
- int error, size, i, bit;
- ntfs_u8 *bmap;
- ntfs_io io;
- ntfs_volume *vol = walk->dir->vol;
-
- /* Check for allocation attribute. */
- allocation = ntfs_find_attr(walk->dir, vol->at_index_allocation, I30);
- if (!allocation) {
- ntfs_u8 bmp[8];
- /* Create index allocation attribute. */
- error = ntfs_create_attr(walk->dir, vol->at_index_allocation,
- I30, 0, 0, &allocation);
- if (error)
- goto err_ret;
- ntfs_bzero(bmp, sizeof(bmp));
- error = ntfs_create_attr(walk->dir, vol->at_bitmap, I30, bmp,
- sizeof(bmp), &bitmap);
- if (error)
- goto err_ret;
- } else
- bitmap = ntfs_find_attr(walk->dir, vol->at_bitmap, I30);
- if (!bitmap) {
- ntfs_error("Directory w/o bitmap\n");
- error = -EINVAL;
- goto err_ret;
- }
- size = bitmap->size;
- bmap = ntfs_malloc(size);
- if (!bmap) {
- error = -ENOMEM;
- goto err_ret;
- }
- io.fn_put = ntfs_put;
- io.fn_get = ntfs_get;
-try_again:
- io.param = bmap;
- io.size = size;
- error = ntfs_read_attr(walk->dir, vol->at_bitmap, I30, 0, &io);
- if (error || (io.size != size && (error = -EIO, 1)))
- goto err_fb_out;
- /* Allocate a bit. */
- for (bit = i = 0; i < size; i++) {
- if (bmap[i] == 0xFF)
- continue;
- bit = ffz(bmap[i]);
- if (bit < 8)
- break;
- }
- if (i >= size) {
- /* FIXME: Extend bitmap. */
- error = -EOPNOTSUPP;
- goto err_fb_out;
- }
- /* Get the byte containing our bit again, now taking the BKL. */
- io.param = bmap;
- io.size = 1;
- lock_kernel();
- error = ntfs_read_attr(walk->dir, vol->at_bitmap, I30, i, &io);
- if (error || (io.size != 1 && (error = -EIO, 1)))
- goto err_unl_out;
- if (ntfs_test_and_set_bit(bmap, bit)) {
- unlock_kernel();
- /* Give other process(es) a chance to finish. */
- schedule();
- goto try_again;
- }
- walk->newblock = (i * 8 + bit) * walk->dir->u.index.clusters_per_record;
- io.param = bmap;
- error = ntfs_write_attr(walk->dir, vol->at_bitmap, I30, i, &io);
- if (error || (io.size != size && (error = -EIO, 1)))
- goto err_unl_out;
- /* Change inode on disk, required when bitmap is resident. */
- error = ntfs_update_inode(walk->dir);
- if (error)
- goto err_unl_out;
- unlock_kernel();
- ntfs_free(bmap);
- /* Check whether record is out of allocated range. */
- size = allocation->size;
- if (walk->newblock * vol->cluster_size >= size) {
- /* Build index record. */
- int hsize;
- int s1 = walk->dir->u.index.recordsize;
- int nr_fix = (s1 >> vol->sector_size) + 1;
- char *record = ntfs_malloc(s1);
- if (!record) {
- error = -ENOMEM;
- goto err_ret;
- }
- ntfs_bzero(record, s1);
- /* Magic */
- ntfs_memcpy(record, "INDX", 4);
- /* Offset to fixups */
- NTFS_PUTU16(record + 4, 0x28);
- /* Number of fixups. */
- NTFS_PUTU16(record + 6, nr_fix);
- /* Log file sequence number - We don't do journalling so we
- * just set it to zero which should be the Right Thing. (AIA) */
- NTFS_PUTU64(record + 8, 0);
- /* VCN of buffer */
- NTFS_PUTU64(record + 0x10, walk->newblock);
- /* Header size. */
- hsize = 0x10 + 2 * nr_fix;
- hsize = (hsize + 7) & ~7; /* Align. */
- NTFS_PUTU16(record + 0x18, hsize);
- /* Total size of record. */
- NTFS_PUTU32(record + 0x20, s1 - 0x18);
- /* Writing the data will extend the attribute. */
- io.param = record;
- io.size = s1;
- io.do_read = 0;
- error = ntfs_readwrite_attr(walk->dir, allocation, size, &io);
- ntfs_free(record);
- if (error || (io.size != s1 && (error = -EIO, 1)))
- goto err_ret;
- error = ntfs_update_inode(walk->dir);
- if (error)
- goto err_ret;
- }
- return 0;
-err_unl_out:
- unlock_kernel();
-err_fb_out:
- ntfs_free(bmap);
-err_ret:
- return error;
-}
-
-/* Write an index block (root or allocation) back to storage.
- * Used is the total number of bytes in buf, including all headers. */
-static int ntfs_index_writeback(ntfs_iterate_s *walk, ntfs_u8 *buf, int block,
- int used)
-{
- ntfs_io io;
- int error;
- ntfs_attribute *a;
- ntfs_volume *vol = walk->dir->vol;
-
- io.fn_put = 0;
- io.fn_get = ntfs_get;
- io.param = buf;
- if (block == -1) { /* Index root. */
- NTFS_PUTU16(buf + 0x14, used - 0x10);
- /* 0x18 is a copy thereof. */
- NTFS_PUTU16(buf + 0x18, used - 0x10);
- io.size = used;
- error = ntfs_write_attr(walk->dir, vol->at_index_root, I30, 0,
- &io);
- if (error || (io.size != used && (error = -EIO, 1)))
- return error;
- /* Shrink if necessary. */
- a = ntfs_find_attr(walk->dir, vol->at_index_root, I30);
- ntfs_resize_attr(walk->dir, a, used);
- } else {
- NTFS_PUTU16(buf + 0x1C, used - 0x18);
- io.size = walk->dir->u.index.recordsize;
- error = ntfs_insert_fixups(buf, io.size);
- if (error) {
- printk(KERN_ALERT "NTFS: ntfs_index_writeback() caught "
- "corrupt index record ntfs record "
- "header. Refusing to write corrupt "
- "data to disk. Unmount and run chkdsk "
- "immediately!\n");
- return -EIO;
- }
- error = ntfs_write_attr(walk->dir, vol->at_index_allocation,
- I30, (__s64)block << vol->cluster_size_bits,
- &io);
- if (error || (io.size != walk->dir->u.index.recordsize &&
- (error = -EIO, 1)))
- return error;
- }
- return 0;
-}
-
-static int ntfs_split_record(ntfs_iterate_s *walk, char *start, int bsize,
- int usize)
-{
- char *entry, *prev;
- ntfs_u8 *newbuf = 0, *middle = 0;
- int error, othersize, mlen;
- ntfs_io io;
- ntfs_volume *vol = walk->dir->vol;
- int oldblock;
-
- error = ntfs_allocate_index_block(walk);
- if (error)
- return error;
- /* This should not happen. */
- if (walk->block == -1) {
- ntfs_error("Trying to split root");
- return -EOPNOTSUPP;
- }
- entry = start + NTFS_GETU16(start + 0x18) + 0x18;
- for (prev = entry; entry - start < usize / 2;
- entry += NTFS_GETU16(entry + 8))
- prev = entry;
- newbuf = ntfs_malloc(vol->index_record_size);
- if (!newbuf)
- return -ENOMEM;
- io.fn_put = ntfs_put;
- io.fn_get = ntfs_get;
- io.param = newbuf;
- io.size = vol->index_record_size;
- /* Read in old header. FIXME: Reading everything is overkill. */
- error = ntfs_read_attr(walk->dir, vol->at_index_allocation, I30,
- (__s64)walk->newblock << vol->cluster_size_bits, &io);
- if (error)
- goto out;
- if (io.size != vol->index_record_size) {
- error = -EIO;
- goto out;
- }
- /* FIXME: Adjust header. */
- /* Copy everything from entry to new block. */
- othersize = usize - (entry - start);
- ntfs_memcpy(newbuf + NTFS_GETU16(newbuf + 0x18) + 0x18, entry,
- othersize);
- /* Copy flags. */
- NTFS_PUTU32(newbuf + 0x24, NTFS_GETU32(start + 0x24));
- error = ntfs_index_writeback(walk, newbuf, walk->newblock,
- othersize + NTFS_GETU16(newbuf + 0x18) + 0x18);
- if (error)
- goto out;
- /* Move prev to walk. */
- mlen = NTFS_GETU16(prev + 0x8);
- /* Remember old child node. */
- if (ntfs_entry_has_subnodes(prev))
- oldblock = NTFS_GETU32(prev + mlen - 8);
- else
- oldblock = -1;
- /* Allow for pointer to subnode. */
- middle = ntfs_malloc(ntfs_entry_has_subnodes(prev) ? mlen : mlen + 8);
- if (!middle){
- error = -ENOMEM;
- goto out;
- }
- ntfs_memcpy(middle, prev, mlen);
- /* Set has_subnodes flag. */
- NTFS_PUTU8(middle + 0xC, NTFS_GETU8(middle + 0xC) | 1);
- /* Middle entry points to block, parent entry will point to newblock. */
- NTFS_PUTU64(middle + mlen - 8, walk->block);
- if (walk->new_entry)
- ntfs_error("Entry not reset");
- walk->new_entry = middle;
- walk->u.flags |= ITERATE_SPLIT_DONE;
- /* Terminate old block. */
- othersize = usize - (prev-start);
- NTFS_PUTU64(prev, 0);
- if (oldblock == -1) {
- NTFS_PUTU32(prev + 8, 0x10);
- NTFS_PUTU32(prev + 0xC, 2);
- othersize += 0x10;
- } else {
- NTFS_PUTU32(prev + 8, 0x18);
- NTFS_PUTU32(prev + 0xC, 3);
- NTFS_PUTU64(prev + 0x10, oldblock);
- othersize += 0x18;
- }
- /* Write back original block. */
- error = ntfs_index_writeback(walk, start, walk->block, othersize);
- out:
- if (newbuf)
- ntfs_free(newbuf);
- if (middle)
- ntfs_free(middle);
- return error;
-}
-
-static int ntfs_dir_insert(ntfs_iterate_s *walk, char *start, char* entry)
-{
- int blocksize, usedsize, error, offset;
- int do_split = 0;
- offset = entry - start;
- if (walk->block == -1) { /* index root */
- blocksize = walk->dir->vol->mft_record_size;
- usedsize = NTFS_GETU16(start + 0x14) + 0x10;
- } else {
- blocksize = walk->dir->u.index.recordsize;
- usedsize = NTFS_GETU16(start + 0x1C) + 0x18;
- }
- if (usedsize + walk->new_entry_size > blocksize) {
- char* s1 = ntfs_malloc(blocksize + walk->new_entry_size);
- if (!s1)
- return -ENOMEM;
- ntfs_memcpy(s1, start, usedsize);
- do_split = 1;
- /* Adjust entry to s1. */
- entry = s1 + (entry - start);
- start = s1;
- }
- ntfs_memmove(entry + walk->new_entry_size, entry, usedsize - offset);
- ntfs_memcpy(entry, walk->new_entry, walk->new_entry_size);
- usedsize += walk->new_entry_size;
- ntfs_free(walk->new_entry);
- walk->new_entry = 0;
- if (do_split) {
- error = ntfs_split_record(walk, start, blocksize, usedsize);
- ntfs_free(start);
- } else {
- error = ntfs_index_writeback(walk, start, walk->block,usedsize);
- if (error)
- return error;
- }
- return 0;
-}
-
-/* Try to split INDEX_ROOT attributes. Return -E2BIG if nothing changed. */
-int ntfs_split_indexroot(ntfs_inode *ino)
-{
- ntfs_attribute *ra;
- ntfs_u8 *root = 0, *index = 0;
- ntfs_io io;
- int error, off, i, bsize, isize;
- ntfs_iterate_s walk;
-
- ra = ntfs_find_attr(ino, ino->vol->at_index_root, I30);
- if (!ra)
- return -ENOTDIR;
- bsize = ino->vol->mft_record_size;
- root = ntfs_malloc(bsize);
- if (!root)
- return -E2BIG;
- io.fn_put = ntfs_put;
- io.param = root;
- io.size = bsize;
- error = ntfs_read_attr(ino, ino->vol->at_index_root, I30, 0, &io);
- if (error)
- goto out;
- off = 0x20;
- /* Count number of entries. */
- for (i = 0; ntfs_entry_is_used(root + off); i++)
- off += NTFS_GETU16(root + off + 8);
- if (i <= 2) {
- /* We don't split small index roots. */
- error = -E2BIG;
- goto out;
- }
- index = ntfs_malloc(ino->vol->index_record_size);
- if (!index) {
- error = -ENOMEM;
- goto out;
- }
- walk.dir = ino;
- walk.block = -1;
- walk.result = walk.new_entry = 0;
- walk.name = 0;
- error = ntfs_allocate_index_block(&walk);
- if (error)
- goto out;
- /* Write old root to new index block. */
- io.param = index;
- io.size = ino->vol->index_record_size;
- error = ntfs_read_attr(ino, ino->vol->at_index_allocation, I30,
- (__s64)walk.newblock << ino->vol->cluster_size_bits, &io);
- if (error)
- goto out;
- isize = NTFS_GETU16(root + 0x18) - 0x10;
- ntfs_memcpy(index + NTFS_GETU16(index + 0x18) + 0x18, root+0x20, isize);
- /* Copy flags. */
- NTFS_PUTU32(index + 0x24, NTFS_GETU32(root + 0x1C));
- error = ntfs_index_writeback(&walk, index, walk.newblock,
- isize + NTFS_GETU16(index + 0x18) + 0x18);
- if (error)
- goto out;
- /* Mark root as split. */
- NTFS_PUTU32(root + 0x1C, 1);
- /* Truncate index root. */
- NTFS_PUTU64(root + 0x20, 0);
- NTFS_PUTU32(root + 0x28, 0x18);
- NTFS_PUTU32(root + 0x2C, 3);
- NTFS_PUTU64(root + 0x30, walk.newblock);
- error = ntfs_index_writeback(&walk, root, -1, 0x38);
- out:
- ntfs_free(root);
- ntfs_free(index);
- return error;
-}
-
-/* The entry has been found. Copy the result in the caller's buffer */
-static int ntfs_copyresult(char *dest, char *source)
-{
- int length = NTFS_GETU16(source + 8);
- ntfs_memcpy(dest, source, length);
- return 1;
-}
-
-/* Use $UpCase some day. */
-static inline unsigned short ntfs_my_toupper(ntfs_volume *vol, ntfs_u16 x)
-{
- /* We should read any pending rest of $UpCase here. */
- if (x >= vol->upcase_length)
- return x;
- return vol->upcase[x];
-}
-
-/* Everything passed in walk and entry. */
-static int ntfs_my_strcmp(ntfs_iterate_s *walk, const unsigned char *entry)
-{
- int lu = *(entry + 0x50);
- int i;
-
- ntfs_u16* name = (ntfs_u16*)(entry + 0x52);
- ntfs_volume *vol = walk->dir->vol;
- for (i = 0; i < lu && i < walk->namelen; i++)
- if (ntfs_my_toupper(vol, NTFS_GETU16(name + i)) !=
- ntfs_my_toupper(vol, NTFS_GETU16(walk->name + i)))
- break;
- if (i == lu && i == walk->namelen)
- return 0;
- if (i == lu)
- return 1;
- if (i == walk->namelen)
- return -1;
- if (ntfs_my_toupper(vol, NTFS_GETU16(name + i)) <
- ntfs_my_toupper(vol, NTFS_GETU16(walk->name + i)))
- return 1;
- return -1;
-}
-
-/* Necessary forward declaration. */
-static int ntfs_getdir_iterate(ntfs_iterate_s *walk, char *start, char *entry);
-
-/* Parse a block of entries. Load the block, fix it up, and iterate over the
- * entries. The block is given as virtual cluster number. */
-static int ntfs_getdir_record(ntfs_iterate_s *walk, int block)
-{
- int length = walk->dir->u.index.recordsize;
- char *record = (char*)ntfs_malloc(length);
- char *offset;
- int retval,error;
- int oldblock;
- ntfs_io io;
-
- if (!record)
- return -ENOMEM;
- io.fn_put = ntfs_put;
- io.param = record;
- io.size = length;
- /* Read the block from the index allocation attribute. */
- error = ntfs_read_attr(walk->dir, walk->dir->vol->at_index_allocation,
- I30, (__s64)block << walk->dir->vol->cluster_size_bits, &io);
- if (error || io.size != length) {
- ntfs_error("read failed\n");
- ntfs_free(record);
- return 0;
- }
- if (!ntfs_check_index_record(walk->dir, record)) {
- ntfs_error("%x is not an index record\n", block);
- ntfs_free(record);
- return 0;
- }
- offset = record + NTFS_GETU16(record + 0x18) + 0x18;
- oldblock = walk->block;
- walk->block = block;
- retval = ntfs_getdir_iterate(walk, record, offset);
- walk->block = oldblock;
- ntfs_free(record);
- return retval;
-}
-
-/* Go down to the next block of entries. These collate before the current
- * entry. */
-static int ntfs_descend(ntfs_iterate_s *walk, ntfs_u8 *start, ntfs_u8 *entry)
-{
- int length = NTFS_GETU16(entry + 8);
- int nextblock = NTFS_GETU32(entry + length - 8);
- int error;
-
- if (!ntfs_entry_has_subnodes(entry)) {
- ntfs_error("illegal ntfs_descend call\n");
- return 0;
- }
- error = ntfs_getdir_record(walk, nextblock);
- if (!error && walk->type == DIR_INSERT &&
- (walk->u.flags & ITERATE_SPLIT_DONE)) {
- /* Split has occurred. Adjust entry, insert new_entry. */
- NTFS_PUTU32(entry + length - 8, walk->newblock);
- /* Reset flags, as the current block might be split again. */
- walk->u.flags &= ~ITERATE_SPLIT_DONE;
- error = ntfs_dir_insert(walk, start, entry);
- }
- return error;
-}
-
-static int ntfs_getdir_iterate_byposition(ntfs_iterate_s *walk, char* start,
- char *entry)
-{
- int retval = 0;
- int curpos = 0, destpos = 0;
- int length;
- if (walk->u.pos != 0) {
- if (ntfs_is_top(walk->u.pos))
- return 0;
- destpos = ntfs_pop(&walk->u.pos);
- }
- while (1) {
- if (walk->u.pos == 0) {
- if (ntfs_entry_has_subnodes(entry))
- ntfs_descend(walk, start, entry);
- else
- walk->u.pos = ntfs_top();
- if (ntfs_is_top(walk->u.pos) &&
- !ntfs_entry_is_used(entry))
- return 1;
- walk->u.pos = ntfs_push(walk->u.pos, curpos);
- return 1;
- }
- if (curpos == destpos) {
- if (!ntfs_is_top(walk->u.pos) &&
- ntfs_entry_has_subnodes(entry)) {
- retval = ntfs_descend(walk, start, entry);
- if (retval) {
- walk->u.pos = ntfs_push(walk->u.pos,
- curpos);
- return retval;
- }
- if (!ntfs_entry_is_used(entry))
- return 0;
- walk->u.pos = 0;
- }
- if (ntfs_entry_is_used(entry)) {
- retval = ntfs_copyresult(walk->result, entry);
- walk->u.pos = 0;
- } else {
- walk->u.pos = ntfs_top();
- return 0;
- }
- }
- curpos++;
- if (!ntfs_entry_is_used(entry))
- break;
- length = NTFS_GETU16(entry + 8);
- if (!length) {
- ntfs_error("infinite loop\n");
- break;
- }
- entry += length;
- }
- return -1;
-}
-
-/* Iterate over a list of entries, either from an index block, or from the
- * index root.
- * If searching BY_POSITION, pop the top index from the position. If the
- * position stack is empty then, return the item at the index and set the
- * position to the next entry. If the position stack is not empty,
- * recursively proceed for subnodes. If the entry at the position is the
- * 'end of dir' entry, return 'not found' and the empty stack.
- * If searching BY_NAME, walk through the items until found or until
- * one item is collated after the requested item. In the former case, return
- * the result. In the latter case, recursively proceed to the subnodes.
- * If 'end of dir' is reached, the name is not in the directory */
-static int ntfs_getdir_iterate(ntfs_iterate_s *walk, char *start, char *entry)
-{
- int length;
- int cmp;
-
- if (walk->type == BY_POSITION)
- return ntfs_getdir_iterate_byposition(walk, start, entry);
- do {
- /* If the current entry is a real one, compare with the
- * requested item. If the current entry is the last item, it
- * is always larger than the requested item. */
- cmp = ntfs_entry_is_used(entry) ?
- ntfs_my_strcmp(walk,entry) : -1;
- switch (walk->type) {
- case BY_NAME:
- switch (cmp) {
- case -1:
- return ntfs_entry_has_subnodes(entry) ?
- ntfs_descend(walk, start, entry) : 0;
- case 0:
- return ntfs_copyresult(walk->result, entry);
- case 1:
- break;
- }
- break;
- case DIR_INSERT:
- switch (cmp) {
- case -1:
- return ntfs_entry_has_subnodes(entry) ?
- ntfs_descend(walk, start, entry) :
- ntfs_dir_insert(walk, start, entry);
- case 0:
- return -EEXIST;
- case 1:
- break;
- }
- break;
- default:
- ntfs_error("TODO\n"); /* FIXME: ? */
- }
- if (!ntfs_entry_is_used(entry))
- break;
- length = NTFS_GETU16(entry + 8);
- if (!length) {
- ntfs_error("infinite loop\n");
- break;
- }
- entry += length;
- } while (1);
- return 0;
-}
-
-/* Tree walking is done using position numbers. The following numbers have a
- * special meaning:
- * 0 start (.)
- * -1 no more entries
- * -2 ..
- * All other numbers encode sequences of indices. The sequence a, b, c is
- * encoded as <stop><c><b><a>, where <foo> is the encoding of foo. The
- * first few integers are encoded as follows:
- * 0: 0000 1: 0010 2: 0100 3: 0110
- * 4: 1000 5: 1010 6: 1100 stop: 1110
- * 7: 000001 8: 000101 9: 001001 10: 001101
- * The least significant bits give the width of this encoding, the other bits
- * encode the value, starting from the first value of the interval.
- * tag width first value last value
- * 0 3 0 6
- * 01 4 7 22
- * 011 5 23 54
- * 0111 6 55 119
- * More values are hopefully not needed, as the file position has currently
- * 64 bits in total. */
-
-/* Find an entry in the directory. Return 0 if not found, otherwise copy the
- * entry to the result buffer. */
-int ntfs_getdir(ntfs_iterate_s *walk)
-{
- int length = walk->dir->vol->mft_record_size;
- int retval, error;
- /* Start at the index root. */
- char *root = ntfs_malloc(length);
- ntfs_io io;
-
- if (!root)
- return -ENOMEM;
- io.fn_put = ntfs_put;
- io.param = root;
- io.size = length;
- error = ntfs_read_attr(walk->dir, walk->dir->vol->at_index_root, I30,
- 0, &io);
- if (error) {
- ntfs_error("Not a directory\n");
- return 0;
- }
- walk->block = -1;
- /* FIXME: Move these to walk. */
- walk->dir->u.index.recordsize = NTFS_GETU32(root + 0x8);
- walk->dir->u.index.clusters_per_record = NTFS_GETU32(root + 0xC);
- /* FIXME: Consistency check. */
- /* Skip header. */
- retval = ntfs_getdir_iterate(walk, root, root + 0x20);
- ntfs_free(root);
- return retval;
-}
-
-/* Find an entry in the directory by its position stack. Iteration starts
- * if the stack is 0, in which case the position is set to the first item
- * in the directory. If the position is nonzero, return the item at the
- * position and change the position to the next item. The position is -1
- * if there are no more items. */
-int ntfs_getdir_byposition(ntfs_iterate_s *walk)
-{
- walk->type = BY_POSITION;
- return ntfs_getdir(walk);
-}
-
-/* Find an entry in the directory by its name. Return 0 if not found. */
-int ntfs_getdir_byname(ntfs_iterate_s *walk)
-{
- walk->type = BY_NAME;
- return ntfs_getdir(walk);
-}
-
-int ntfs_getdir_unsorted(ntfs_inode *ino, u32 *p_high, u32 *p_low,
- int (*cb)(ntfs_u8 *, void *), void *param)
-{
- s64 ib_ofs;
- char *buf = 0, *entry = 0;
- ntfs_attribute *attr;
- ntfs_volume *vol;
- int byte, bit, err = 0;
- u32 start, finish, ibs, max_size;
- ntfs_io io;
- u8 ibs_bits;
-
- if (!ino) {
- ntfs_error(__FUNCTION__ "(): No inode! Returning -EINVAL.\n");
- return -EINVAL;
- }
- vol = ino->vol;
- if (!vol) {
- ntfs_error(__FUNCTION__ "(): Inode 0x%lx has no volume. "
- "Returning -EINVAL.\n", ino->i_number);
- return -EINVAL;
- }
- ntfs_debug(DEBUG_DIR3, __FUNCTION__ "(): Unsorted 1: Entering for "
- "inode 0x%lx, p_high = 0x%x, p_low = 0x%x.\n",
- ino->i_number, *p_high, *p_low);
- if (!*p_high) {
- /* We are still in the index root. */
- buf = ntfs_malloc(io.size = vol->mft_record_size);
- if (!buf)
- return -ENOMEM;
- io.fn_put = ntfs_put;
- io.param = buf;
- err = ntfs_read_attr(ino, vol->at_index_root, I30, 0, &io);
- if (err || !io.size)
- goto read_err_ret;
- ino->u.index.recordsize = ibs = NTFS_GETU32(buf + 0x8);
- ino->u.index.clusters_per_record = NTFS_GETU32(buf + 0xC);
- entry = buf + 0x20;
- ntfs_debug(DEBUG_DIR3, __FUNCTION__ "(): Unsorted 2: In index "
- "root.\n");
- ibs_bits = ffs(ibs) - 1;
- /* Compensate for faked "." and "..". */
- start = 2;
- } else { /* We are in an index record. */
- io.size = ibs = ino->u.index.recordsize;
- buf = ntfs_malloc(ibs);
- if (!buf)
- return -ENOMEM;
- ibs_bits = ffs(ibs) - 1;
- io.fn_put = ntfs_put;
- io.param = buf;
- /*
- * 0 is index root, index allocation starts at 1 and works in
- * units of index block size (ibs).
- */
- ib_ofs = (s64)(*p_high - 1) << ibs_bits;
- err = ntfs_read_attr(ino, vol->at_index_allocation, I30, ib_ofs,
- &io);
- if (err || io.size != ibs)
- goto read_err_ret;
- if (!ntfs_check_index_record(ino, buf)) {
- ntfs_error(__FUNCTION__ "(): Index block 0x%x is not "
- "an index record. Returning "
- "-ENOTDIR.\n", *p_high - 1);
- ntfs_free(buf);
- return -ENOTDIR;
- }
- entry = buf + 0x18 + NTFS_GETU16(buf + 0x18);
- ntfs_debug(DEBUG_DIR3, __FUNCTION__ "(): Unsorted 3: In index "
- "allocation.\n");
- start = 0;
- }
- /* Process the entries. */
- finish = *p_low;
- for (; entry < (buf + ibs) && ntfs_entry_is_used(entry);
- entry += NTFS_GETU16(entry + 8)) {
- if (start < finish) {
- /* Skip entries that were already processed. */
- ntfs_debug(DEBUG_DIR3, __FUNCTION__ "(): Unsorted 4: "
- "Skipping already processed entry "
- "p_high 0x%x, p_low 0x%x.\n", *p_high,
- start);
- start++;
- continue;
- }
- ntfs_debug(DEBUG_DIR3, __FUNCTION__ "(): Unsorted 5: "
- "Processing entry p_high 0x%x, p_low 0x%x.\n",
- *p_high, *p_low);
- if ((err = cb(entry, param))) {
- /* filldir signalled us to stop. */
- ntfs_debug(DEBUG_DIR3, __FUNCTION__ "(): "
- "Unsorted 6: cb returned %i, "
- "returning 0, p_high 0x%x, p_low 0x%x."
- "\n", *p_high, *p_low);
- ntfs_free(buf);
- return 0;
- }
- ++*p_low;
- }
- ntfs_debug(DEBUG_DIR3, __FUNCTION__ "(): Unsorted 7: After processing "
- "entries, p_high 0x%x, p_low 0x%x.\n", *p_high, *p_low);
- /* We have to locate the next record. */
- ntfs_free(buf);
- buf = 0;
- *p_low = 0;
- attr = ntfs_find_attr(ino, vol->at_bitmap, I30);
- if (!attr) {
- /* Directory does not have index bitmap and index allocation. */
- *p_high = 0x7fff;
- ntfs_debug(DEBUG_DIR3, __FUNCTION__ "(): Unsorted 8: No index "
- "allocation. Returning 0, p_high 0x7fff, "
- "p_low 0x0.\n");
- return 0;
- }
- max_size = attr->size;
- if (max_size > 0x7fff >> 3) {
- ntfs_error(__FUNCTION__ "(): Directory too large. Visible "
- "length is truncated.\n");
- max_size = 0x7fff >> 3;
- }
- buf = ntfs_malloc(max_size);
- if (!buf)
- return -ENOMEM;
- io.param = buf;
- io.size = max_size;
- err = ntfs_read_attr(ino, vol->at_bitmap, I30, 0, &io);
- if (err || io.size != max_size)
- goto read_err_ret;
- attr = ntfs_find_attr(ino, vol->at_index_allocation, I30);
- if (!attr) {
- ntfs_free(buf);
- ntfs_debug(DEBUG_DIR3, __FUNCTION__ "(): Unsorted 9: Find "
- "attr failed. Returning -EIO.\n");
- return -EIO;
- }
- if (attr->resident) {
- ntfs_free(buf);
- ntfs_debug(DEBUG_DIR3, __FUNCTION__ "(): Unsorted 9.5: IA is "
- "resident. Not allowed. Returning EINVAL.\n");
- return -EINVAL;
- }
- /* Loop while going through non-allocated index records. */
- max_size <<= 3;
- while (1) {
- if (++*p_high >= 0x7fff) {
- ntfs_error(__FUNCTION__ "(): Unsorted 10: Directory "
- "inode 0x%lx overflowed the maximum "
- "number of index allocation buffers "
- "the driver can cope with. Pretending "
- "to be at end of directory.\n",
- ino->i_number);
- goto fake_eod;
- }
- if (*p_high > max_size || (s64)*p_high << ibs_bits >
- attr->initialized) {
-fake_eod:
- /* No more index records. */
- *p_high = 0x7fff;
- *p_low = 0;
- ntfs_free(buf);
- ntfs_debug(DEBUG_DIR3, __FUNCTION__ "(): Unsorted "
- "10.5: No more index records. "
- "Returning 0, p_high 0x7fff, p_low "
- "0.\n");
- return 0;
- }
- byte = (ntfs_cluster_t)(*p_high - 1);
- bit = 1 << (byte & 7);
- byte >>= 3;
- if ((buf[byte] & bit))
- break;
- };
- ntfs_debug(DEBUG_DIR3, __FUNCTION__ "(): Unsorted 11: Done. "
- "Returning 0, p_high 0x%x, p_low 0x%x.\n", *p_high,
- *p_low);
- ntfs_free(buf);
- return 0;
-read_err_ret:
- if (!err)
- err = -EIO;
- ntfs_error(__FUNCTION__ "(): Read failed. Returning error code %i.\n",
- err);
- ntfs_free(buf);
- return err;
-}
-
-int ntfs_dir_add(ntfs_inode *dir, ntfs_inode *new, ntfs_attribute *name)
-{
- ntfs_iterate_s walk;
- int nsize, esize;
- ntfs_u8* entry, *ndata;
- int error;
-
- walk.type = DIR_INSERT;
- walk.dir = dir;
- walk.u.flags = 0;
- nsize = name->size;
- ndata = name->d.data;
- walk.name = (ntfs_u16*)(ndata + 0x42);
- walk.namelen = NTFS_GETU8(ndata + 0x40);
- walk.new_entry_size = esize = (nsize + 0x10 + 7) & ~7;
- walk.new_entry = entry = ntfs_malloc(esize);
- if (!entry)
- return -ENOMEM;
- NTFS_PUTINUM(entry, new);
- NTFS_PUTU16(entry + 0x8, esize); /* Size of entry. */
- NTFS_PUTU16(entry + 0xA, nsize); /* Size of original name attribute. */
- NTFS_PUTU16(entry + 0xC, 0); /* Flags. */
- NTFS_PUTU16(entry + 0xE, 0); /* Reserved. */
- ntfs_memcpy(entry + 0x10, ndata, nsize);
- ntfs_bzero(entry + 0x10 + nsize, esize - 0x10 - nsize);
- error = ntfs_getdir(&walk);
- if (walk.new_entry)
- ntfs_free(walk.new_entry);
- return error;
-}
-
-#if 0
-int ntfs_dir_add1(ntfs_inode *dir, const char* name, int namelen,
- ntfs_inode *ino)
-{
- ntfs_iterate_s walk;
- int error;
- int nsize;
- char *entry;
- ntfs_attribute *name_attr;
- error = ntfs_decodeuni(dir->vol, name, namelen, &walk.name,
- &walk.namelen);
- if (error)
- return error;
- /* FIXME: Set flags. */
- walk.type = DIR_INSERT;
- walk.dir = dir;
- /* walk.new = ino; */
- /* Prepare new entry. */
- /* Round up to a multiple of 8. */
- walk.new_entry_size = nsize = ((0x52 + 2 * walk.namelen + 7) / 8) * 8;
- walk.new_entry = entry = ntfs_malloc(nsize);
- if (!entry)
- return -ENOMEM;
- ntfs_bzero(entry, nsize);
- NTFS_PUTINUM(entry, ino);
- NTFS_PUTU16(entry + 8, nsize);
- NTFS_PUTU16(entry + 0xA, 0x42 + 2 * namelen); /* FIXME: Size of name
- * attribute. */
- NTFS_PUTU32(entry + 0xC, 0); /* FIXME: D-F? */
- name_attr = ntfs_find_attr(ino, vol->at_file_name, 0);
- /* FIXME: multiple names */
- if (!name_attr || !name_attr->resident)
- return -EIDRM;
- /* Directory, file stamps, sizes, filename. */
- ntfs_memcpy(entry + 0x10, name_attr->d.data, 0x42 + 2 * namelen);
- error = ntfs_getdir(&walk);
- ntfs_free(walk.name);
- return error;
-}
-#endif
-
-/* Fills out and creates an INDEX_ROOT attribute. */
-int ntfs_add_index_root(ntfs_inode *ino, int type)
-{
- ntfs_attribute *da;
- ntfs_u8 data[0x30]; /* 0x20 header, 0x10 last entry. */
- char name[10];
-
- NTFS_PUTU32(data, type);
- /* Collation rule. 1 == COLLATION_FILENAME */
- NTFS_PUTU32(data + 4, 1);
- NTFS_PUTU32(data + 8, ino->vol->index_record_size);
- NTFS_PUTU32(data + 0xC, ino->vol->index_clusters_per_record);
- /* Byte offset to first INDEX_ENTRY. */
- NTFS_PUTU32(data + 0x10, 0x10);
- /* Size of entries, including header. */
- NTFS_PUTU32(data + 0x14, 0x20);
- NTFS_PUTU32(data + 0x18, 0x20);
- /* No index allocation, yet. */
- NTFS_PUTU32(data + 0x1C, 0);
- /* Add last entry. */
- /* Indexed MFT record. */
- NTFS_PUTU64(data + 0x20, 0);
- /* Size of entry. */
- NTFS_PUTU32(data + 0x28, 0x10);
- /* Flags: Last entry, no child nodes. */
- NTFS_PUTU32(data + 0x2C, 2);
- /* Compute name. */
- ntfs_indexname(name, type);
- return ntfs_create_attr(ino, ino->vol->at_index_root, name,
- data, sizeof(data), &da);
-}
-
-int ntfs_mkdir(ntfs_inode *dir, const char *name, int namelen,
- ntfs_inode *result)
-{
- int error;
-
- error = ntfs_alloc_inode(dir, result, name, namelen, NTFS_AFLAG_DIR);
- if (error)
- goto out;
- error = ntfs_add_index_root(result, 0x30);
- if (error)
- goto out;
- /* Set directory bit. */
- result->attr[0x16] |= 2;
- error = ntfs_update_inode(dir);
- if (error)
- goto out;
- error = ntfs_update_inode(result);
- if (error)
- goto out;
- out:
- return error;
-}
-
diff --git a/fs/ntfs/dir.h b/fs/ntfs/dir.h
deleted file mode 100644
index 3ded6dca3faf..000000000000
--- a/fs/ntfs/dir.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * dir.h - Header file for dir.c
- *
- * Copyright (C) 1997 Régis Duchesne
- */
-#define ITERATE_SPLIT_DONE 1
-
-enum ntfs_iterate_e {
- BY_POSITION,
- BY_NAME,
- DIR_INSERT
-};
-
-/* not all fields are used for all operations */
-typedef struct ntfs_iterate_s {
- enum ntfs_iterate_e type;
- ntfs_inode *dir;
- union{
- ntfs_u64 pos;
- int flags;
- }u;
- char *result; /* pointer to entry if found */
- ntfs_u16* name;
- int namelen;
- int block; /* current index record */
- int newblock; /* index record created in a split */
- char *new_entry;
- int new_entry_size;
- /*ntfs_inode* new;*/
-} ntfs_iterate_s;
-
-int ntfs_getdir_unsorted(ntfs_inode *ino, ntfs_u32 *p_high, ntfs_u32* p_low,
- int (*cb)(ntfs_u8*, void*), void *param);
-
-int ntfs_getdir_byname(ntfs_iterate_s *walk);
-
-int ntfs_dir_add(ntfs_inode *dir, ntfs_inode *new, ntfs_attribute *name);
-
-int ntfs_check_index_record(ntfs_inode *ino, char *record);
-
-int ntfs_getdir_byposition(ntfs_iterate_s *walk);
-
-int ntfs_mkdir(ntfs_inode* dir,const char* name,int namelen, ntfs_inode *ino);
-
-int ntfs_split_indexroot(ntfs_inode *ino);
-
-int ntfs_add_index_root(ntfs_inode *ino, int type);
-
diff --git a/fs/ntfs/fs.c b/fs/ntfs/fs.c
deleted file mode 100644
index a74fb1fd4499..000000000000
--- a/fs/ntfs/fs.c
+++ /dev/null
@@ -1,1233 +0,0 @@
-/*
- * fs.c - NTFS driver for Linux 2.4.x
- *
- * Legato Systems, Inc. (http://www.legato.com) have sponsored Anton
- * Altaparmakov to develop NTFS on Linux since June 2001.
- *
- * Copyright (C) 1995-1997, 1999 Martin von Löwis
- * Copyright (C) 1996 Richard Russon
- * Copyright (C) 1996-1997 Régis Duchesne
- * Copyright (C) 2000-2001, Anton Altaparmakov (AIA)
- */
-
-#include <linux/config.h>
-#include <linux/errno.h>
-#include "ntfstypes.h"
-#include "struct.h"
-#include "util.h"
-#include "inode.h"
-#include "super.h"
-#include "dir.h"
-#include "support.h"
-#include "macros.h"
-#include "sysctl.h"
-#include "attr.h"
-#include <linux/module.h>
-#include <asm/uaccess.h>
-#include <linux/locks.h>
-#include <linux/init.h>
-#include <linux/smp_lock.h>
-#include <linux/blkdev.h>
-#include <asm/page.h>
-#include <linux/nls.h>
-#include <linux/ntfs_fs.h>
-
-/* Forward declarations. */
-static struct inode_operations ntfs_dir_inode_operations;
-static struct file_operations ntfs_dir_operations;
-
-#define ITEM_SIZE 2040
-
-/* Io functions to user space. */
-static void ntfs_putuser(ntfs_io* dest, void *src, ntfs_size_t len)
-{
- copy_to_user(dest->param, src, len);
- dest->param += len;
-}
-
-#ifdef CONFIG_NTFS_RW
-struct ntfs_getuser_update_vm_s {
- const char *user;
- struct inode *ino;
- loff_t off;
-};
-
-static void ntfs_getuser_update_vm(void *dest, ntfs_io *src, ntfs_size_t len)
-{
- struct ntfs_getuser_update_vm_s *p = src->param;
-
- copy_from_user(dest, p->user, len);
- p->user += len;
- p->off += len;
-}
-#endif
-
-/* loff_t is 64 bit signed, so is cool. */
-static ssize_t ntfs_read(struct file *filp, char *buf, size_t count,loff_t *off)
-{
- int error;
- ntfs_io io;
- ntfs_attribute *attr;
- ntfs_inode *ino = NTFS_I(filp->f_dentry->d_inode);
-
- /* Inode is not properly initialized. */
- if (!ino)
- return -EINVAL;
- ntfs_debug(DEBUG_OTHER, "ntfs_read %x, %Lx, %x ->",
- (unsigned)ino->i_number, (unsigned long long)*off,
- (unsigned)count);
- attr = ntfs_find_attr(ino, ino->vol->at_data, NULL);
- /* Inode has no unnamed data attribute. */
- if (!attr) {
- ntfs_debug(DEBUG_OTHER, "ntfs_read: $DATA not found!\n");
- return -EINVAL;
- }
- if (attr->flags & ATTR_IS_ENCRYPTED)
- return -EACCES;
- /* Read the data. */
- io.fn_put = ntfs_putuser;
- io.fn_get = 0;
- io.param = buf;
- io.size = count;
- error = ntfs_read_attr(ino, ino->vol->at_data, NULL, *off, &io);
- if (error && !io.size) {
- ntfs_debug(DEBUG_OTHER, "ntfs_read: read_attr failed with "
- "error %i, io size %u.\n", error, io.size);
- return error;
- }
- *off += io.size;
- ntfs_debug(DEBUG_OTHER, "ntfs_read: finished. read %u bytes.\n",
- io.size);
- return io.size;
-}
-
-#ifdef CONFIG_NTFS_RW
-static ssize_t ntfs_write(struct file *filp, const char *buf, size_t count,
- loff_t *pos)
-{
- int err;
- struct inode *vfs_ino = filp->f_dentry->d_inode;
- ntfs_inode *ntfs_ino = NTFS_I(vfs_ino);
- ntfs_attribute *data;
- ntfs_io io;
- struct ntfs_getuser_update_vm_s param;
-
- if (!ntfs_ino)
- return -EINVAL;
- ntfs_debug(DEBUG_LINUX, __FUNCTION__ "(): Entering for inode 0x%lx, "
- "*pos 0x%Lx, count 0x%x.\n", ntfs_ino->i_number, *pos,
- count);
- /* Allows to lock fs ro at any time. */
- if (vfs_ino->i_sb->s_flags & MS_RDONLY)
- return -EROFS;
- data = ntfs_find_attr(ntfs_ino, ntfs_ino->vol->at_data, NULL);
- if (!data)
- return -EINVAL;
- /* Evaluating O_APPEND is the file system's job... */
- if (filp->f_flags & O_APPEND)
- *pos = vfs_ino->i_size;
- if (!data->resident && *pos + count > data->allocated) {
- err = ntfs_extend_attr(ntfs_ino, data, *pos + count);
- if (err < 0)
- return err;
- }
- param.user = buf;
- param.ino = vfs_ino;
- param.off = *pos;
- io.fn_put = 0;
- io.fn_get = ntfs_getuser_update_vm;
- io.param = &param;
- io.size = count;
- io.do_read = 0;
- err = ntfs_readwrite_attr(ntfs_ino, data, *pos, &io);
- ntfs_debug(DEBUG_LINUX, __FUNCTION__ "(): Returning %i\n", -err);
- if (!err) {
- *pos += io.size;
- if (*pos > vfs_ino->i_size)
- vfs_ino->i_size = *pos;
- mark_inode_dirty(vfs_ino);
- return io.size;
- }
- return err;
-}
-#endif
-
-struct ntfs_filldir {
- struct inode *dir;
- filldir_t filldir;
- unsigned int type;
- u32 ph, pl;
- void *dirent;
- char *name;
- int namelen;
- int ret_code;
-};
-
-static int ntfs_printcb(ntfs_u8 *entry, void *param)
-{
- unsigned long inum = NTFS_GETU64(entry) & 0xffffffffffff;
- struct ntfs_filldir *nf = param;
- u32 flags = NTFS_GETU32(entry + 0x48);
- char show_sys_files = 0;
- u8 name_len = NTFS_GETU8(entry + 0x50);
- u8 name_type = NTFS_GETU8(entry + 0x51);
- int err;
- unsigned file_type;
-
- switch (nf->type) {
- case ngt_dos:
- /* Don't display long names. */
- if (!(name_type & 2))
- return 0;
- break;
- case ngt_nt:
- /* Don't display short-only names. */
- if ((name_type & 3) == 2)
- return 0;
- break;
- case ngt_posix:
- break;
- case ngt_full:
- show_sys_files = 1;
- break;
- default:
- BUG();
- }
- err = ntfs_encodeuni(NTFS_INO2VOL(nf->dir), (ntfs_u16*)(entry + 0x52),
- name_len, &nf->name, &nf->namelen);
- if (err) {
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Skipping "
- "unrepresentable file.\n");
- err = 0;
- goto err_ret;
- }
- if (!show_sys_files && inum < 0x10UL) {
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Skipping system "
- "file (%s).\n", nf->name);
- err = 0;
- goto err_ret;
- }
- /* Do not return ".", as this is faked. */
- if (nf->namelen == 1 && nf->name[0] == '.') {
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Skipping \".\"\n");
- err = 0;
- goto err_ret;
- }
- nf->name[nf->namelen] = 0;
- if (flags & 0x10000000) /* FILE_ATTR_DUP_FILE_NAME_INDEX_PRESENT */
- file_type = DT_DIR;
- else
- file_type = DT_REG;
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Calling filldir for %s with "
- "len %i, f_pos 0x%Lx, inode %lu, %s.\n",
- nf->name, nf->namelen, (loff_t)(nf->ph << 16) | nf->pl,
- inum, file_type == DT_DIR ? "DT_DIR" : "DT_REG");
- /*
- * Userspace side of filldir expects an off_t rather than an loff_t.
- * And it also doesn't like the most significant bit being set as it
- * then considers the value to be negative. Thus this implementation
- * limits the number of index records to 32766, which should be plenty.
- */
- err = nf->filldir(nf->dirent, nf->name, nf->namelen,
- (loff_t)(nf->ph << 16) | nf->pl, inum, file_type);
- if (err)
- nf->ret_code = err;
-err_ret:
- nf->namelen = 0;
- ntfs_free(nf->name);
- nf->name = NULL;
- return err;
-}
-
-/*
- * readdir returns '.', then '..', then the directory entries in sequence.
- * As the root directory contains an entry for itself, '.' is not emulated for
- * the root directory.
- */
-static int ntfs_readdir(struct file* filp, void *dirent, filldir_t filldir)
-{
- struct inode *dir = filp->f_dentry->d_inode;
- int err;
- struct ntfs_filldir cb;
-
- cb.ret_code = 0;
- cb.pl = filp->f_pos & 0xffff;
- cb.ph = (filp->f_pos >> 16) & 0x7fff;
- filp->f_pos = (loff_t)(cb.ph << 16) | cb.pl;
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Entering for inode %lu, "
- "f_pos 0x%Lx, i_mode 0x%x, i_count %lu.\n", dir->i_ino,
- filp->f_pos, (unsigned int)dir->i_mode,
- atomic_read(&dir->i_count));
- if (!cb.ph) {
- /* Start of directory. Emulate "." and "..". */
- if (!cb.pl) {
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Calling "
- "filldir for . with len 1, f_pos 0x%Lx, "
- "inode %lu, DT_DIR.\n", filp->f_pos,
- dir->i_ino);
- cb.ret_code = filldir(dirent, ".", 1, filp->f_pos,
- dir->i_ino, DT_DIR);
- if (cb.ret_code)
- goto done;
- cb.pl++;
- filp->f_pos = (loff_t)(cb.ph << 16) | cb.pl;
- }
- if (cb.pl == (u32)1) {
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Calling "
- "filldir for .. with len 2, f_pos 0x%Lx, "
- "inode %lu, DT_DIR.\n", filp->f_pos,
- parent_ino(filp->f_dentry));
- cb.ret_code = filldir(dirent, "..", 2, filp->f_pos,
- parent_ino(filp->f_dentry), DT_DIR);
- if (cb.ret_code)
- goto done;
- cb.pl++;
- filp->f_pos = (loff_t)(cb.ph << 16) | cb.pl;
- }
- } else if (cb.ph >= 0x7fff)
- /* End of directory. */
- goto done;
- cb.dir = dir;
- cb.filldir = filldir;
- cb.dirent = dirent;
- cb.type = NTFS_INO2VOL(dir)->ngt;
- do {
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Looking for next "
- "file using ntfs_getdir_unsorted(), f_pos "
- "0x%Lx.\n", (loff_t)(cb.ph << 16) | cb.pl);
- err = ntfs_getdir_unsorted(NTFS_I(dir), &cb.ph, &cb.pl,
- ntfs_printcb, &cb);
- } while (!err && !cb.ret_code && cb.ph < 0x7fff);
- filp->f_pos = (loff_t)(cb.ph << 16) | cb.pl;
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): After ntfs_getdir_unsorted()"
- " calls, f_pos 0x%Lx.\n", filp->f_pos);
- if (!err) {
-done:
-#ifdef DEBUG
- if (!cb.ret_code)
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): EOD, f_pos "
- "0x%Lx, returning 0.\n", filp->f_pos);
- else
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): filldir "
- "returned %i, returning 0, f_pos "
- "0x%Lx.\n", cb.ret_code, filp->f_pos);
-#endif
- return 0;
- }
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Returning %i, f_pos 0x%Lx.\n",
- err, filp->f_pos);
- return err;
-}
-
-/* Copied from vfat driver. */
-static int simple_getbool(char *s, int *setval)
-{
- if (s) {
- if (!strcmp(s, "1") || !strcmp(s, "yes") || !strcmp(s, "true"))
- *setval = 1;
- else if (!strcmp(s, "0") || !strcmp(s, "no") ||
- !strcmp(s, "false"))
- *setval = 0;
- else
- return 0;
- } else
- *setval = 1;
- return 1;
-}
-
-/*
- * This needs to be outside parse_options() otherwise a remount will reset
- * these unintentionally.
- */
-static void init_ntfs_super_block(ntfs_volume* vol)
-{
- vol->uid = vol->gid = 0;
- vol->umask = 0077;
- vol->ngt = ngt_nt;
- vol->nls_map = (void*)-1;
- vol->mft_zone_multiplier = -1;
-}
-
-/* Parse the (re)mount options. */
-static int parse_options(ntfs_volume *vol, char *opt)
-{
- char *value; /* Defaults if not specified and !remount. */
- ntfs_uid_t uid = -1; /* 0, root user only */
- ntfs_gid_t gid = -1; /* 0, root user only */
- int umask = -1; /* 0077, owner access only */
- unsigned int ngt = -1; /* ngt_nt */
- void *nls_map = NULL; /* Try to load the default NLS. */
- int use_utf8 = -1; /* If no NLS specified and loading the default
- NLS failed use utf8. */
- int mft_zone_mul = -1; /* 1 */
-
- if (!opt)
- goto done;
- for (opt = strtok(opt, ","); opt; opt = strtok(NULL, ",")) {
- if ((value = strchr(opt, '=')) != NULL)
- *value ++= '\0';
- if (strcmp(opt, "uid") == 0) {
- if (!value || !*value)
- goto needs_arg;
- uid = simple_strtoul(value, &value, 0);
- if (*value) {
- printk(KERN_ERR "NTFS: uid invalid argument\n");
- return 0;
- }
- } else if (strcmp(opt, "gid") == 0) {
- if (!value || !*value)
- goto needs_arg;
- gid = simple_strtoul(value, &value, 0);
- if (*value) {
- printk(KERN_ERR "NTFS: gid invalid argument\n");
- return 0;
- }
- } else if (strcmp(opt, "umask") == 0) {
- if (!value || !*value)
- goto needs_arg;
- umask = simple_strtoul(value, &value, 0);
- if (*value) {
- printk(KERN_ERR "NTFS: umask invalid "
- "argument\n");
- return 0;
- }
- } else if (strcmp(opt, "mft_zone_multiplier") == 0) {
- unsigned long ul;
-
- if (!value || !*value)
- goto needs_arg;
- ul = simple_strtoul(value, &value, 0);
- if (*value) {
- printk(KERN_ERR "NTFS: mft_zone_multiplier "
- "invalid argument\n");
- return 0;
- }
- if (ul >= 1 && ul <= 4)
- mft_zone_mul = ul;
- else {
- mft_zone_mul = 1;
- printk(KERN_WARNING "NTFS: mft_zone_multiplier "
- "out of range. Setting to 1.\n");
- }
- } else if (strcmp(opt, "posix") == 0) {
- int val;
- if (!value || !*value)
- goto needs_arg;
- if (!simple_getbool(value, &val))
- goto needs_bool;
- ngt = val ? ngt_posix : ngt_nt;
- } else if (strcmp(opt, "show_sys_files") == 0) {
- int val = 0;
- if (!value || !*value)
- val = 1;
- else if (!simple_getbool(value, &val))
- goto needs_bool;
- ngt = val ? ngt_full : ngt_nt;
- } else if (strcmp(opt, "iocharset") == 0) {
- if (!value || !*value)
- goto needs_arg;
- nls_map = load_nls(value);
- if (!nls_map) {
- printk(KERN_ERR "NTFS: charset not found");
- return 0;
- }
- } else if (strcmp(opt, "utf8") == 0) {
- int val = 0;
- if (!value || !*value)
- val = 1;
- else if (!simple_getbool(value, &val))
- goto needs_bool;
- use_utf8 = val;
- } else {
- printk(KERN_ERR "NTFS: unkown option '%s'\n", opt);
- return 0;
- }
- }
-done:
- if (use_utf8 == -1) {
- /* utf8 was not specified at all. */
- if (!nls_map) {
- /*
- * No NLS was specified. If first mount, load the
- * default NLS, otherwise don't change the NLS setting.
- */
- if (vol->nls_map == (void*)-1)
- vol->nls_map = load_nls_default();
- } else {
- /* If an NLS was already loaded, unload it first. */
- if (vol->nls_map && vol->nls_map != (void*)-1)
- unload_nls(vol->nls_map);
- /* Use the specified NLS. */
- vol->nls_map = nls_map;
- }
- } else {
- /* utf8 was specified. */
- if (use_utf8 && nls_map) {
- unload_nls(nls_map);
- printk(KERN_ERR "NTFS: utf8 cannot be combined with "
- "iocharset.\n");
- return 0;
- }
- /* If an NLS was already loaded, unload it first. */
- if (vol->nls_map && vol->nls_map != (void*)-1)
- unload_nls(vol->nls_map);
- if (!use_utf8) {
- /* utf8 was specified as false. */
- if (!nls_map)
- /* No NLS was specified, load the default. */
- vol->nls_map = load_nls_default();
- else
- /* Use the specified NLS. */
- vol->nls_map = nls_map;
- } else
- /* utf8 was specified as true. */
- vol->nls_map = NULL;
- }
- if (uid != -1)
- vol->uid = uid;
- if (gid != -1)
- vol->gid = gid;
- if (umask != -1)
- vol->umask = (ntmode_t)umask;
- if (ngt != -1)
- vol->ngt = ngt;
- if (mft_zone_mul != -1) {
- /* mft_zone_multiplier was specified. */
- if (vol->mft_zone_multiplier != -1) {
- /* This is a remount, ignore a change and warn user. */
- if (vol->mft_zone_multiplier != mft_zone_mul)
- printk(KERN_WARNING "NTFS: Ignoring changes in "
- "mft_zone_multiplier on "
- "remount. If you want to "
- "change this you need to "
- "umount and mount again.\n");
- } else
- /* Use the specified multiplier. */
- vol->mft_zone_multiplier = mft_zone_mul;
- } else if (vol->mft_zone_multiplier == -1)
- /* No multiplier specified and first mount, so set default. */
- vol->mft_zone_multiplier = 1;
- return 1;
-needs_arg:
- printk(KERN_ERR "NTFS: %s needs an argument", opt);
- return 0;
-needs_bool:
- printk(KERN_ERR "NTFS: %s needs boolean argument", opt);
- return 0;
-}
-
-static struct dentry *ntfs_lookup(struct inode *dir, struct dentry *d)
-{
- struct inode *res = 0;
- char *item = 0;
- ntfs_iterate_s walk;
- int err;
-
- ntfs_debug(DEBUG_NAME1, __FUNCTION__ "(): Looking up %s in directory "
- "ino 0x%x.\n", d->d_name.name, (unsigned)dir->i_ino);
- walk.name = NULL;
- walk.namelen = 0;
- /* Convert to wide string. */
- lock_kernel();
- err = ntfs_decodeuni(NTFS_INO2VOL(dir), (char*)d->d_name.name,
- d->d_name.len, &walk.name, &walk.namelen);
- if (err)
- goto err_ret;
- item = ntfs_malloc(ITEM_SIZE);
- if (!item) {
- err = -ENOMEM;
- goto err_ret;
- }
- /* ntfs_getdir will place the directory entry into item, and the first
- * long long is the MFT record number. */
- walk.type = BY_NAME;
- walk.dir = NTFS_I(dir);
- walk.result = item;
- if (ntfs_getdir_byname(&walk))
- res = iget(dir->i_sb, NTFS_GETU32(item));
- d_add(d, res);
- ntfs_free(item);
- ntfs_free(walk.name);
- unlock_kernel();
- /* Always return success, the dcache will handle negative entries. */
- return NULL;
-err_ret:
- ntfs_free(walk.name);
- unlock_kernel();
- return ERR_PTR(err);
-}
-
-static struct file_operations ntfs_file_operations = {
- llseek: generic_file_llseek,
- read: ntfs_read,
-#ifdef CONFIG_NTFS_RW
- write: ntfs_write,
-#endif
- open: generic_file_open,
-};
-
-static struct inode_operations ntfs_inode_operations;
-
-#ifdef CONFIG_NTFS_RW
-static int ntfs_create(struct inode* dir, struct dentry *d, int mode)
-{
- struct inode *r = 0;
- ntfs_inode *ino = 0;
- ntfs_volume *vol;
- int error = 0;
- ntfs_attribute *si;
-
- lock_kernel();
- r = new_inode(dir->i_sb);
- if (!r) {
- error = -ENOMEM;
- goto fail;
- }
- ntfs_debug(DEBUG_OTHER, "ntfs_create %s\n", d->d_name.name);
- vol = NTFS_INO2VOL(dir);
- ino = NTFS_I(r);
- ino->u.index.recordsize = 0;
- ino->u.index.clusters_per_record = 0;
- error = ntfs_alloc_file(NTFS_I(dir), ino, (char*)d->d_name.name,
- d->d_name.len);
- if (error) {
- ntfs_error("ntfs_alloc_file FAILED: error = %i", error);
- goto fail;
- }
- /* Not doing this one was causing a huge amount of corruption! Now the
- * bugger bytes the dust! (-8 (AIA) */
- r->i_ino = ino->i_number;
- error = ntfs_update_inode(ino);
- if (error)
- goto fail;
- error = ntfs_update_inode(NTFS_I(dir));
- if (error)
- goto fail;
- r->i_uid = vol->uid;
- r->i_gid = vol->gid;
- /* FIXME: dirty? dev? */
- /* Get the file modification times from the standard information. */
- si = ntfs_find_attr(ino, vol->at_standard_information, NULL);
- if (si) {
- char *attr = si->d.data;
- r->i_atime = ntfs_ntutc2unixutc(NTFS_GETU64(attr + 0x18));
- r->i_ctime = ntfs_ntutc2unixutc(NTFS_GETU64(attr));
- r->i_mtime = ntfs_ntutc2unixutc(NTFS_GETU64(attr + 8));
- }
- /* It's not a directory */
- r->i_op = &ntfs_inode_operations;
- r->i_fop = &ntfs_file_operations;
- r->i_mode = S_IFREG | S_IRUGO;
-#ifdef CONFIG_NTFS_RW
- r->i_mode |= S_IWUGO;
-#endif
- r->i_mode &= ~vol->umask;
- unlock_kernel();
- insert_inode_hash(r);
- d_instantiate(d, r);
- return 0;
- fail:
- unlock_kernel();
- if (r)
- iput(r);
- return error;
-}
-
-static int _linux_ntfs_mkdir(struct inode *dir, struct dentry* d, int mode)
-{
- int error;
- struct inode *r = 0;
- ntfs_volume *vol;
- ntfs_inode *ino;
- ntfs_attribute *si;
-
- lock_kernel();
- ntfs_debug (DEBUG_DIR1, "mkdir %s in %x\n", d->d_name.name, dir->i_ino);
- error = -ENAMETOOLONG;
- if (d->d_name.len > /* FIXME: */ 255)
- goto out;
- error = -EIO;
- r = new_inode(dir->i_sb);
- if (!r)
- goto out;
- vol = NTFS_INO2VOL(dir);
- ino = NTFS_I(r);
- error = ntfs_mkdir(NTFS_I(dir), d->d_name.name, d->d_name.len,
- ino);
- if (error)
- goto out;
- /* Not doing this one was causing a huge amount of corruption! Now the
- * bugger bytes the dust! (-8 (AIA) */
- r->i_ino = ino->i_number;
- r->i_uid = vol->uid;
- r->i_gid = vol->gid;
- si = ntfs_find_attr(ino, vol->at_standard_information, NULL);
- if (si) {
- char *attr = si->d.data;
- r->i_atime = ntfs_ntutc2unixutc(NTFS_GETU64(attr + 0x18));
- r->i_ctime = ntfs_ntutc2unixutc(NTFS_GETU64(attr));
- r->i_mtime = ntfs_ntutc2unixutc(NTFS_GETU64(attr + 8));
- }
- /* It's a directory. */
- r->i_op = &ntfs_dir_inode_operations;
- r->i_fop = &ntfs_dir_operations;
- r->i_mode = S_IFDIR | S_IRUGO | S_IXUGO;
-#ifdef CONFIG_NTFS_RW
- r->i_mode |= S_IWUGO;
-#endif
- r->i_mode &= ~vol->umask;
-
- insert_inode_hash(r);
- d_instantiate(d, r);
- error = 0;
- out:
- ntfs_debug (DEBUG_DIR1, "mkdir returns %d\n", error);
- unlock_kernel();
- return error;
-}
-#endif
-
-static struct file_operations ntfs_dir_operations = {
- read: generic_read_dir,
- readdir: ntfs_readdir,
-};
-
-static struct inode_operations ntfs_dir_inode_operations = {
- lookup: ntfs_lookup,
-#ifdef CONFIG_NTFS_RW
- create: ntfs_create,
- mkdir: _linux_ntfs_mkdir,
-#endif
-};
-
-/* ntfs_read_inode() is called by the Virtual File System (the kernel layer
- * that deals with filesystems) when iget is called requesting an inode not
- * already present in the inode table. Typically filesystems have separate
- * inode_operations for directories, files and symlinks. */
-static void ntfs_read_inode(struct inode* inode)
-{
- ntfs_volume *vol;
- ntfs_inode *ino;
- ntfs_attribute *data;
- ntfs_attribute *si;
-
- vol = NTFS_INO2VOL(inode);
- inode->i_mode = 0;
- ntfs_debug(DEBUG_OTHER, "ntfs_read_inode 0x%lx\n", inode->i_ino);
- switch (inode->i_ino) {
- /* Those are loaded special files. */
- case FILE_Mft:
- if (!vol->mft_ino || ((vol->ino_flags & 1) == 0))
- goto sys_file_error;
- ntfs_memcpy(NTFS_I(inode), vol->mft_ino, sizeof(ntfs_inode));
- ino = vol->mft_ino;
- vol->mft_ino = NTFS_I(inode);
- vol->ino_flags &= ~1;
- ntfs_free(ino);
- ino = vol->mft_ino;
- ntfs_debug(DEBUG_OTHER, "Opening $MFT!\n");
- break;
- case FILE_MftMirr:
- if (!vol->mftmirr || ((vol->ino_flags & 2) == 0))
- goto sys_file_error;
- ntfs_memcpy(NTFS_I(inode), vol->mftmirr, sizeof(ntfs_inode));
- ino = vol->mftmirr;
- vol->mftmirr = NTFS_I(inode);
- vol->ino_flags &= ~2;
- ntfs_free(ino);
- ino = vol->mftmirr;
- ntfs_debug(DEBUG_OTHER, "Opening $MFTMirr!\n");
- break;
- case FILE_BitMap:
- if (!vol->bitmap || ((vol->ino_flags & 4) == 0))
- goto sys_file_error;
- ntfs_memcpy(NTFS_I(inode), vol->bitmap, sizeof(ntfs_inode));
- ino = vol->bitmap;
- vol->bitmap = NTFS_I(inode);
- vol->ino_flags &= ~4;
- ntfs_free(ino);
- ino = vol->bitmap;
- ntfs_debug(DEBUG_OTHER, "Opening $Bitmap!\n");
- break;
- case FILE_LogFile ... FILE_AttrDef:
- /* No need to log root directory accesses. */
- case FILE_Boot ... FILE_UpCase:
- ntfs_debug(DEBUG_OTHER, "Opening system file %i!\n",
- inode->i_ino);
- default:
- ino = NTFS_I(inode);
- ino->u.index.recordsize = 0;
- ino->u.index.clusters_per_record = 0;
- if (ntfs_init_inode(ino, NTFS_INO2VOL(inode), inode->i_ino)) {
- ntfs_debug(DEBUG_OTHER, "NTFS: Error loading inode "
- "0x%x\n", (unsigned int)inode->i_ino);
- return;
- }
- }
- /* Set uid/gid from mount options */
- inode->i_uid = vol->uid;
- inode->i_gid = vol->gid;
- inode->i_nlink = 1;
- /* Use the size of the data attribute as file size */
- data = ntfs_find_attr(ino, vol->at_data, NULL);
- if (!data)
- inode->i_size = 0;
- else
- inode->i_size = data->size;
- /* Get the file modification times from the standard information. */
- si = ntfs_find_attr(ino, vol->at_standard_information, NULL);
- if (si) {
- char *attr = si->d.data;
- inode->i_atime = ntfs_ntutc2unixutc(NTFS_GETU64(attr + 0x18));
- inode->i_ctime = ntfs_ntutc2unixutc(NTFS_GETU64(attr));
- inode->i_mtime = ntfs_ntutc2unixutc(NTFS_GETU64(attr + 8));
- }
- /* If it has an index root, it's a directory. */
- if (ntfs_find_attr(ino, vol->at_index_root, "$I30")) {
- ntfs_attribute *at;
- at = ntfs_find_attr(ino, vol->at_index_allocation, "$I30");
- inode->i_size = at ? at->size : 0;
- inode->i_op = &ntfs_dir_inode_operations;
- inode->i_fop = &ntfs_dir_operations;
- inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO;
- } else {
- inode->i_op = &ntfs_inode_operations;
- inode->i_fop = &ntfs_file_operations;
- inode->i_mode = S_IFREG | S_IRUGO;
- }
-#ifdef CONFIG_NTFS_RW
- if (!data || !(data->flags & (ATTR_IS_COMPRESSED | ATTR_IS_ENCRYPTED)))
- inode->i_mode |= S_IWUGO;
-#endif
- inode->i_mode &= ~vol->umask;
- return;
-sys_file_error:
- ntfs_error("Critical error. Tried to call ntfs_read_inode() before we "
- "have completed read_super() or VFS error.\n");
- // FIXME: Should we panic() at this stage?
-}
-
-#ifdef CONFIG_NTFS_RW
-static void ntfs_write_inode(struct inode *ino, int unused)
-{
- lock_kernel();
- ntfs_debug(DEBUG_LINUX, "ntfs_write_inode 0x%x\n", ino->i_ino);
- ntfs_update_inode(NTFS_I(ino));
- unlock_kernel();
-}
-#endif
-
-static void _ntfs_clear_inode(struct inode *inode)
-{
- ntfs_inode *ino;
- ntfs_volume *vol;
-
- lock_kernel();
- ntfs_debug(DEBUG_OTHER, "_ntfs_clear_inode 0x%x\n", inode->i_ino);
- vol = NTFS_INO2VOL(inode);
- if (!vol)
- ntfs_error("_ntfs_clear_inode: vol = NTFS_INO2VOL(inode) is "
- "NULL.\n");
- switch (inode->i_ino) {
- case FILE_Mft:
- if (vol->mft_ino && ((vol->ino_flags & 1) == 0)) {
- ino = (ntfs_inode*)ntfs_malloc(sizeof(ntfs_inode));
- ntfs_memcpy(ino, NTFS_I(inode), sizeof(ntfs_inode));
- vol->mft_ino = ino;
- vol->ino_flags |= 1;
- goto unl_out;
- }
- break;
- case FILE_MftMirr:
- if (vol->mftmirr && ((vol->ino_flags & 2) == 0)) {
- ino = (ntfs_inode*)ntfs_malloc(sizeof(ntfs_inode));
- ntfs_memcpy(ino, NTFS_I(inode), sizeof(ntfs_inode));
- vol->mftmirr = ino;
- vol->ino_flags |= 2;
- goto unl_out;
- }
- break;
- case FILE_BitMap:
- if (vol->bitmap && ((vol->ino_flags & 4) == 0)) {
- ino = (ntfs_inode*)ntfs_malloc(sizeof(ntfs_inode));
- ntfs_memcpy(ino, NTFS_I(inode), sizeof(ntfs_inode));
- vol->bitmap = ino;
- vol->ino_flags |= 4;
- goto unl_out;
- }
- break;
- default:
- /* Nothing. Just clear the inode and exit. */
- }
- ntfs_clear_inode(NTFS_I(inode));
-unl_out:
- unlock_kernel();
- return;
-}
-
-/* Called when umounting a filesystem by do_umount() in fs/super.c. */
-static void ntfs_put_super(struct super_block *sb)
-{
- ntfs_volume *vol;
-
- ntfs_debug(DEBUG_OTHER, "ntfs_put_super\n");
- vol = NTFS_SB2VOL(sb);
- ntfs_release_volume(vol);
- if (vol->nls_map)
- unload_nls(vol->nls_map);
- ntfs_debug(DEBUG_OTHER, "ntfs_put_super: done\n");
-}
-
-/* Called by the kernel when asking for stats. */
-static int ntfs_statfs(struct super_block *sb, struct statfs *sf)
-{
- struct inode *mft;
- ntfs_volume *vol;
- __s64 size;
- int error;
-
- ntfs_debug(DEBUG_OTHER, "ntfs_statfs\n");
- vol = NTFS_SB2VOL(sb);
- sf->f_type = NTFS_SUPER_MAGIC;
- sf->f_bsize = vol->cluster_size;
- error = ntfs_get_volumesize(NTFS_SB2VOL(sb), &size);
- if (error)
- return error;
- sf->f_blocks = size; /* Volumesize is in clusters. */
- size = (__s64)ntfs_get_free_cluster_count(vol->bitmap);
- /* Just say zero if the call failed. */
- if (size < 0LL)
- size = 0;
- sf->f_bfree = sf->f_bavail = size;
- ntfs_debug(DEBUG_OTHER, "ntfs_statfs: calling mft = iget(sb, "
- "FILE_Mft)\n");
- mft = iget(sb, FILE_Mft);
- ntfs_debug(DEBUG_OTHER, "ntfs_statfs: iget(sb, FILE_Mft) returned "
- "0x%x\n", mft);
- if (!mft)
- return -EIO;
- sf->f_files = mft->i_size >> vol->mft_record_size_bits;
- ntfs_debug(DEBUG_OTHER, "ntfs_statfs: calling iput(mft)\n");
- iput(mft);
- /* Should be read from volume. */
- sf->f_namelen = 255;
- return 0;
-}
-
-/* Called when remounting a filesystem by do_remount_sb() in fs/super.c. */
-static int ntfs_remount_fs(struct super_block *sb, int *flags, char *options)
-{
- if (!parse_options(NTFS_SB2VOL(sb), options))
- return -EINVAL;
- return 0;
-}
-
-/* Define the super block operation that are implemented */
-
-static kmem_cache_t * ntfs_inode_cachep;
-
-static struct inode *__ntfs_alloc_inode(struct super_block *sb)
-{
- struct ntfs_i *ei;
- ei = (struct ntfs_i *)kmem_cache_alloc(ntfs_inode_cachep, SLAB_KERNEL);
- if (!ei)
- return NULL;
- return &ei->vfs_inode;
-}
-
-static void ntfs_destroy_inode(struct inode *inode)
-{
- kmem_cache_free(ntfs_inode_cachep, ntfs_i(inode));
-}
-
-static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
-{
- struct ntfs_i *ei = (struct ntfs_i *) foo;
-
- if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
- SLAB_CTOR_CONSTRUCTOR)
- inode_init_once(&ei->vfs_inode);
-}
-
-static int init_inodecache(void)
-{
- ntfs_inode_cachep = kmem_cache_create("ntfs_inode_cache",
- sizeof(struct ntfs_i),
- 0, SLAB_HWCACHE_ALIGN,
- init_once, NULL);
- if (ntfs_inode_cachep == NULL)
- return -ENOMEM;
- return 0;
-}
-
-static void destroy_inodecache(void)
-{
- if (kmem_cache_destroy(ntfs_inode_cachep))
- printk(KERN_INFO "ntfs_inode_cache: not all structures were freed\n");
-}
-static struct super_operations ntfs_super_operations = {
- alloc_inode: __ntfs_alloc_inode,
- destroy_inode: ntfs_destroy_inode,
- read_inode: ntfs_read_inode,
-#ifdef CONFIG_NTFS_RW
- write_inode: ntfs_write_inode,
-#endif
- put_super: ntfs_put_super,
- statfs: ntfs_statfs,
- remount_fs: ntfs_remount_fs,
- clear_inode: _ntfs_clear_inode,
-};
-
-/**
- * is_boot_sector_ntfs - check an NTFS boot sector for validity
- * @b: buffer containing bootsector to check
- *
- * Check whether @b contains a valid NTFS boot sector.
- * Return 1 if @b is a valid NTFS bootsector or 0 if not.
- */
-static int is_boot_sector_ntfs(ntfs_u8 *b)
-{
- ntfs_u32 i;
-
- /* FIXME: We don't use checksumming yet as NT4(SP6a) doesn't either...
- * But we might as well have the code ready to do it. (AIA) */
-#if 0
- /* Calculate the checksum. */
- if (b < b + 0x50) {
- ntfs_u32 *u;
- ntfs_u32 *bi = (ntfs_u32 *)(b + 0x50);
-
- for (u = bi, i = 0; u < bi; ++u)
- i += NTFS_GETU32(*u);
- }
-#endif
- /* Check magic is "NTFS " */
- if (b[3] != 0x4e) goto not_ntfs;
- if (b[4] != 0x54) goto not_ntfs;
- if (b[5] != 0x46) goto not_ntfs;
- if (b[6] != 0x53) goto not_ntfs;
- for (i = 7; i < 0xb; ++i)
- if (b[i] != 0x20) goto not_ntfs;
- /* Check bytes per sector value is between 512 and 4096. */
- if (b[0xb] != 0) goto not_ntfs;
- if (b[0xc] > 0x10) goto not_ntfs;
- /* Check sectors per cluster value is valid. */
- switch (b[0xd]) {
- case 1: case 2: case 4: case 8: case 16:
- case 32: case 64: case 128:
- break;
- default:
- goto not_ntfs;
- }
- /* Check reserved sectors value and four other fields are zero. */
- for (i = 0xe; i < 0x15; ++i)
- if (b[i] != 0) goto not_ntfs;
- if (b[0x16] != 0) goto not_ntfs;
- if (b[0x17] != 0) goto not_ntfs;
- for (i = 0x20; i < 0x24; ++i)
- if (b[i] != 0) goto not_ntfs;
- /* Check clusters per file record segment value is valid. */
- if (b[0x40] < 0xe1 || b[0x40] > 0xf7) {
- switch (b[0x40]) {
- case 1: case 2: case 4: case 8: case 16: case 32: case 64:
- break;
- default:
- goto not_ntfs;
- }
- }
- /* Check clusters per index block value is valid. */
- if (b[0x44] < 0xe1 || b[0x44] > 0xf7) {
- switch (b[0x44]) {
- case 1: case 2: case 4: case 8: case 16: case 32: case 64:
- break;
- default:
- goto not_ntfs;
- }
- }
- return 1;
-not_ntfs:
- return 0;
-}
-
-/* Called to mount a filesystem by read_super() in fs/super.c.
- * Return a super block, the main structure of a filesystem.
- *
- * NOTE : Don't store a pointer to an option, as the page containing the
- * options is freed after ntfs_read_super() returns.
- *
- * NOTE : A context switch can happen in kernel code only if the code blocks
- * (= calls schedule() in kernel/sched.c). */
-static int ntfs_fill_super(struct super_block *sb, void *options, int silent)
-{
- ntfs_volume *vol;
- struct buffer_head *bh;
- int i, to_read, blocksize;
-
- ntfs_debug(DEBUG_OTHER, "ntfs_read_super\n");
- vol = NTFS_SB2VOL(sb);
- init_ntfs_super_block(vol);
- if (!parse_options(vol, (char*)options))
- goto ntfs_read_super_vol;
- blocksize = sb_min_blocksize(sb, 512);
- if (!blocksize) {
- ntfs_error("Unable to set blocksize.\n");
- goto ntfs_read_super_vol;
- }
- /* Read the super block (boot block). */
- if (!(bh = sb_bread(sb, 0))) {
- ntfs_error("Reading super block failed\n");
- goto ntfs_read_super_unl;
- }
- ntfs_debug(DEBUG_OTHER, "Done reading boot block\n");
- /* Check for valid 'NTFS' boot sector. */
- if (!is_boot_sector_ntfs(bh->b_data)) {
- ntfs_debug(DEBUG_OTHER, "Not a NTFS volume\n");
- bforget(bh);
- goto ntfs_read_super_unl;
- }
- ntfs_debug(DEBUG_OTHER, "Going to init volume\n");
- if (ntfs_init_volume(vol, bh->b_data) < 0) {
- ntfs_debug(DEBUG_OTHER, "Init volume failed.\n");
- bforget(bh);
- goto ntfs_read_super_unl;
- }
- ntfs_debug(DEBUG_OTHER, "$Mft at cluster 0x%lx\n", vol->mft_lcn);
- brelse(bh);
- NTFS_SB(vol) = sb;
- if (vol->cluster_size > PAGE_SIZE) {
- ntfs_error("Partition cluster size is not supported yet (it "
- "is > max kernel blocksize).\n");
- goto ntfs_read_super_unl;
- }
- ntfs_debug(DEBUG_OTHER, "Done to init volume\n");
- /* Inform the kernel that a device block is a NTFS cluster. */
- if (!sb_set_blocksize(sb, vol->cluster_size)) {
- ntfs_error("Cluster size too small for device.\n");
- goto ntfs_read_super_unl;
- }
- ntfs_debug(DEBUG_OTHER, "set_blocksize\n");
- /* Allocate an MFT record (MFT record can be smaller than a cluster). */
- i = vol->cluster_size;
- if (i < vol->mft_record_size)
- i = vol->mft_record_size;
- if (!(vol->mft = ntfs_malloc(i)))
- goto ntfs_read_super_unl;
-
- /* Read at least the MFT record for $Mft. */
- to_read = vol->mft_clusters_per_record;
- if (to_read < 1)
- to_read = 1;
- for (i = 0; i < to_read; i++) {
- if (!(bh = sb_bread(sb, vol->mft_lcn + i))) {
- ntfs_error("Could not read $Mft record 0\n");
- goto ntfs_read_super_mft;
- }
- ntfs_memcpy(vol->mft + ((__s64)i << vol->cluster_size_bits),
- bh->b_data, vol->cluster_size);
- brelse(bh);
- ntfs_debug(DEBUG_OTHER, "Read cluster 0x%x\n",
- vol->mft_lcn + i);
- }
- /* Check and fixup this MFT record */
- if (!ntfs_check_mft_record(vol, vol->mft)){
- ntfs_error("Invalid $Mft record 0\n");
- goto ntfs_read_super_mft;
- }
- /* Inform the kernel about which super operations are available. */
- sb->s_op = &ntfs_super_operations;
- sb->s_magic = NTFS_SUPER_MAGIC;
- sb->s_maxbytes = MAX_LFS_FILESIZE;
- ntfs_debug(DEBUG_OTHER, "Reading special files\n");
- if (ntfs_load_special_files(vol)) {
- ntfs_error("Error loading special files\n");
- goto ntfs_read_super_mft;
- }
- ntfs_debug(DEBUG_OTHER, "Getting RootDir\n");
- /* Get the root directory. */
- if (!(sb->s_root = d_alloc_root(iget(sb, FILE_root)))) {
- ntfs_error("Could not get root dir inode\n");
- goto ntfs_read_super_mft;
- }
- return 0;
-ntfs_read_super_mft:
- ntfs_free(vol->mft);
-ntfs_read_super_unl:
-ntfs_read_super_vol:
- ntfs_debug(DEBUG_OTHER, "read_super: done\n");
- return -EINVAL;
-}
-
-/* Define the filesystem */
-static struct super_block *ntfs_get_sb(struct file_system_type *fs_type,
- int flags, char *dev_name, void *data)
-{
- return get_sb_bdev(fs_type, flags, dev_name, data, ntfs_fill_super);
-}
-
-static struct file_system_type ntfs_fs_type = {
- owner: THIS_MODULE,
- name: "ntfs",
- get_sb: ntfs_get_sb,
- fs_flags: FS_REQUIRES_DEV,
-};
-
-static int __init init_ntfs_fs(void)
-{
- int err;
- /* Comment this if you trust klogd. There are reasons not to trust it */
-#if defined(DEBUG) && !defined(MODULE)
- console_verbose();
-#endif
- printk(KERN_NOTICE "NTFS driver v" NTFS_VERSION " [Flags: R/"
-#ifdef CONFIG_NTFS_RW
- "W"
-#else
- "O"
-#endif
-#ifdef DEBUG
- " DEBUG"
-#endif
-#ifdef MODULE
- " MODULE"
-#endif
- "]\n");
- SYSCTL(1);
- ntfs_debug(DEBUG_OTHER, "registering %s\n", ntfs_fs_type.name);
- err = init_inodecache();
- if (err)
- goto out1;
- err = register_filesystem(&ntfs_fs_type);
- if (err)
- goto out;
- return 0;
-out:
- destroy_inodecache();
-out1:
- SYSCTL(0);
- return err;
-}
-
-static void __exit exit_ntfs_fs(void)
-{
- SYSCTL(0);
- ntfs_debug(DEBUG_OTHER, "unregistering %s\n", ntfs_fs_type.name);
- unregister_filesystem(&ntfs_fs_type);
- destroy_inodecache();
-}
-
-EXPORT_NO_SYMBOLS;
-/*
- * Not strictly true. The driver was written originally by Martin von Löwis.
- * I am just maintaining and rewriting it.
- */
-MODULE_AUTHOR("Anton Altaparmakov <aia21@cus.cam.ac.uk>");
-MODULE_DESCRIPTION("Linux NTFS driver");
-MODULE_LICENSE("GPL");
-#ifdef DEBUG
-MODULE_PARM(ntdebug, "i");
-MODULE_PARM_DESC(ntdebug, "Debug level");
-#endif
-
-module_init(init_ntfs_fs)
-module_exit(exit_ntfs_fs)
-
diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c
deleted file mode 100644
index 108465acc2ce..000000000000
--- a/fs/ntfs/inode.c
+++ /dev/null
@@ -1,2317 +0,0 @@
-/*
- * inode.c
- *
- * Copyright (C) 1995-1999 Martin von Löwis
- * Copyright (C) 1996 Albert D. Cahalan
- * Copyright (C) 1996-1997 Régis Duchesne
- * Copyright (C) 1998 Joseph Malicki
- * Copyright (C) 1999 Steve Dodd
- * Copyright (C) 2000-2001 Anton Altaparmakov (AIA)
- */
-#include "ntfstypes.h"
-#include "ntfsendian.h"
-#include "struct.h"
-#include "inode.h"
-#include <linux/errno.h>
-#include "macros.h"
-#include "attr.h"
-#include "super.h"
-#include "dir.h"
-#include "support.h"
-#include "util.h"
-#include <linux/ntfs_fs.h>
-#include <linux/smp_lock.h>
-
-typedef struct {
- int recno;
- unsigned char *record;
-} ntfs_mft_record;
-
-typedef struct {
- int size;
- int count;
- ntfs_mft_record *records;
-} ntfs_disk_inode;
-
-static void ntfs_fill_mft_header(ntfs_u8 *mft, int rec_size, int seq_no,
- int links, int flags)
-{
- int fixup_ofs = 0x2a;
- int fixup_cnt = rec_size / NTFS_SECTOR_SIZE + 1;
- int attr_ofs = (fixup_ofs + 2 * fixup_cnt + 7) & ~7;
-
- NTFS_PUTU32(mft + 0x00, 0x454c4946); /* FILE */
- NTFS_PUTU16(mft + 0x04, fixup_ofs); /* Offset to fixup. */
- NTFS_PUTU16(mft + 0x06, fixup_cnt); /* Number of fixups. */
- NTFS_PUTU64(mft + 0x08, 0); /* Logical sequence number. */
- NTFS_PUTU16(mft + 0x10, seq_no); /* Sequence number. */
- NTFS_PUTU16(mft + 0x12, links); /* Hard link count. */
- NTFS_PUTU16(mft + 0x14, attr_ofs); /* Offset to attributes. */
- NTFS_PUTU16(mft + 0x16, flags); /* Flags: 1 = In use,
- 2 = Directory. */
- NTFS_PUTU32(mft + 0x18, attr_ofs + 8); /* Bytes in use. */
- NTFS_PUTU32(mft + 0x1c, rec_size); /* Total allocated size. */
- NTFS_PUTU64(mft + 0x20, 0); /* Base mft record. */
- NTFS_PUTU16(mft + 0x28, 0); /* Next attr instance. */
- NTFS_PUTU16(mft + fixup_ofs, 1); /* Fixup word. */
- NTFS_PUTU32(mft + attr_ofs, (__u32)-1); /* End of attributes marker. */
-}
-
-/*
- * Search in an inode an attribute by type and name.
- * FIXME: Check that when attributes are inserted all attribute list
- * attributes are expanded otherwise need to modify this function to deal
- * with attribute lists. (AIA)
- */
-ntfs_attribute *ntfs_find_attr(ntfs_inode *ino, int type, char *name)
-{
- int i;
-
- if (!ino) {
- ntfs_error("ntfs_find_attr: NO INODE!\n");
- return 0;
- }
- for (i = 0; i < ino->attr_count; i++) {
- if (type < ino->attrs[i].type)
- return 0;
- if (type == ino->attrs[i].type) {
- if (!name) {
- if (!ino->attrs[i].name)
- return ino->attrs + i;
- } else if (ino->attrs[i].name &&
- !ntfs_ua_strncmp(ino->attrs[i].name, name,
- strlen(name)))
- return ino->attrs + i;
- }
- }
- return 0;
-}
-
-/*
- * Insert all attributes from the record mftno of the MFT in the inode ino.
- * If mftno is a base mft record we abort as soon as we find the attribute
- * list, but only on the first pass. We will get called later when the attribute
- * list attribute is being parsed so we need to distinguish the two cases.
- * FIXME: We should be performing structural consistency checks. (AIA)
- * Return 0 on success or -errno on error.
- */
-static int ntfs_insert_mft_attributes(ntfs_inode* ino, char *mft, int mftno)
-{
- int i, error, type, len, present = 0;
- char *it;
-
- /* Check for duplicate extension record. */
- for(i = 0; i < ino->record_count; i++)
- if (ino->records[i] == mftno) {
- if (i)
- return 0;
- present = 1;
- break;
- }
- if (!present) {
- /* (re-)allocate space if necessary. */
- if (ino->record_count % 8 == 0) {
- int *new;
-
- new = ntfs_malloc((ino->record_count + 8) *
- sizeof(int));
- if (!new)
- return -ENOMEM;
- if (ino->records) {
- for (i = 0; i < ino->record_count; i++)
- new[i] = ino->records[i];
- ntfs_free(ino->records);
- }
- ino->records = new;
- }
- ino->records[ino->record_count] = mftno;
- ino->record_count++;
- }
- it = mft + NTFS_GETU16(mft + 0x14); /* mft->attrs_offset */
- do {
- type = NTFS_GETU32(it);
- len = NTFS_GETU32(it + 4);
- if (type != -1) {
- error = ntfs_insert_attribute(ino, it);
- if (error)
- return error;
- }
- /* If we have just processed the attribute list and this is
- * the first time we are parsing this (base) mft record then we
- * are done so that the attribute list gets parsed before the
- * entries in the base mft record. Otherwise we run into
- * problems with encountering attributes out of order and when
- * this happens with different attribute extents we die. )-:
- * This way we are ok as the attribute list is always sorted
- * fully and correctly. (-: */
- if (type == 0x20 && !present)
- return 0;
- it += len;
- } while (type != -1); /* Attribute listing ends with type -1. */
- return 0;
-}
-
-/*
- * Insert a single specific attribute from the record mftno of the MFT in the
- * inode ino. We disregard the attribute list assuming we have already parsed
- * it.
- * FIXME: We should be performing structural consistency checks. (AIA)
- * Return 0 on success or -errno on error.
- */
-static int ntfs_insert_mft_attribute(ntfs_inode* ino, int mftno,
- ntfs_u8 *attr)
-{
- int i, error, present = 0;
-
- /* Check for duplicate extension record. */
- for(i = 0; i < ino->record_count; i++)
- if (ino->records[i] == mftno) {
- present = 1;
- break;
- }
- if (!present) {
- /* (re-)allocate space if necessary. */
- if (ino->record_count % 8 == 0) {
- int *new;
-
- new = ntfs_malloc((ino->record_count + 8) *
- sizeof(int));
- if (!new)
- return -ENOMEM;
- if (ino->records) {
- for (i = 0; i < ino->record_count; i++)
- new[i] = ino->records[i];
- ntfs_free(ino->records);
- }
- ino->records = new;
- }
- ino->records[ino->record_count] = mftno;
- ino->record_count++;
- }
- if (NTFS_GETU32(attr) == -1) {
- ntfs_debug(DEBUG_FILE3, "ntfs_insert_mft_attribute: attribute "
- "type is -1.\n");
- return 0;
- }
- error = ntfs_insert_attribute(ino, attr);
- if (error)
- return error;
- return 0;
-}
-
-/* Read and insert all the attributes of an 'attribute list' attribute.
- * Return the number of remaining bytes in *plen. */
-static int parse_attributes(ntfs_inode *ino, ntfs_u8 *alist, int *plen)
-{
- ntfs_u8 *mft, *attr;
- int mftno, l, error;
- int last_mft = -1;
- int len = *plen;
- int tries = 0;
-
- if (!ino->attr) {
- ntfs_error("parse_attributes: called on inode 0x%x without a "
- "loaded base mft record.\n", ino->i_number);
- return -EINVAL;
- }
- mft = ntfs_malloc(ino->vol->mft_record_size);
- if (!mft)
- return -ENOMEM;
- while (len > 8) {
- l = NTFS_GETU16(alist + 4);
- if (l > len)
- break;
- /* Process an attribute description. */
- mftno = NTFS_GETU32(alist + 0x10);
- /* FIXME: The mft reference (alist + 0x10) is __s64.
- * - Not a problem unless we encounter a huge partition.
- * - Should be consistency checking the sequence numbers
- * though! This should maybe happen in
- * ntfs_read_mft_record() itself and a hotfix could
- * then occur there or the user notified to run
- * ntfsck. (AIA) */
- if (mftno != ino->i_number && mftno != last_mft) {
-continue_after_loading_mft_data:
- last_mft = mftno;
- error = ntfs_read_mft_record(ino->vol, mftno, mft);
- if (error) {
- if (error == -EINVAL && !tries)
- goto force_load_mft_data;
-failed_reading_mft_data:
- ntfs_debug(DEBUG_FILE3, "parse_attributes: "
- "ntfs_read_mft_record(mftno = 0x%x) "
- "failed\n", mftno);
- ntfs_free(mft);
- return error;
- }
- }
- attr = ntfs_find_attr_in_mft_rec(
- ino->vol, /* ntfs volume */
- mftno == ino->i_number ?/* mft record is: */
- ino->attr: /* base record */
- mft, /* extension record */
- NTFS_GETU32(alist + 0), /* type */
- (wchar_t*)(alist + alist[7]), /* name */
- alist[6], /* name length */
- 1, /* ignore case */
- NTFS_GETU16(alist + 24) /* instance number */
- );
- if (!attr) {
- ntfs_error("parse_attributes: mft records 0x%x and/or "
- "0x%x corrupt!\n", ino->i_number, mftno);
- ntfs_free(mft);
- return -EINVAL; /* FIXME: Better error code? (AIA) */
- }
- error = ntfs_insert_mft_attribute(ino, mftno, attr);
- if (error) {
- ntfs_debug(DEBUG_FILE3, "parse_attributes: "
- "ntfs_insert_mft_attribute(mftno 0x%x, "
- "attribute type 0x%x) failed\n", mftno,
- NTFS_GETU32(alist + 0));
- ntfs_free(mft);
- return error;
- }
- len -= l;
- alist += l;
- }
- ntfs_free(mft);
- *plen = len;
- return 0;
-force_load_mft_data:
-{
- ntfs_u8 *mft2, *attr2;
- int mftno2;
- int last_mft2 = last_mft;
- int len2 = len;
- int error2;
- int found2 = 0;
- ntfs_u8 *alist2 = alist;
- /*
- * We only get here if $DATA wasn't found in $MFT which only happens
- * on volume mount when $MFT has an attribute list and there are
- * attributes before $DATA which are inside extent mft records. So
- * we just skip forward to the $DATA attribute and read that. Then we
- * restart which is safe as an attribute will not be inserted twice.
- *
- * This still will not fix the case where the attribute list is non-
- * resident, larger than 1024 bytes, and the $DATA attribute list entry
- * is not in the first 1024 bytes. FIXME: This should be implemented
- * somehow! Perhaps by passing special error code up to
- * ntfs_load_attributes() so it keeps going trying to get to $DATA
- * regardless. Then it would have to restart just like we do here.
- */
- mft2 = ntfs_malloc(ino->vol->mft_record_size);
- if (!mft2) {
- ntfs_free(mft);
- return -ENOMEM;
- }
- ntfs_memcpy(mft2, mft, ino->vol->mft_record_size);
- while (len2 > 8) {
- l = NTFS_GETU16(alist2 + 4);
- if (l > len2)
- break;
- if (NTFS_GETU32(alist2 + 0x0) < ino->vol->at_data) {
- len2 -= l;
- alist2 += l;
- continue;
- }
- if (NTFS_GETU32(alist2 + 0x0) > ino->vol->at_data) {
- if (found2)
- break;
- /* Uh-oh! It really isn't there! */
- ntfs_error("Either the $MFT is corrupt or, equally "
- "likely, the $MFT is too complex for "
- "the current driver to handle. Please "
- "email the ntfs maintainer that you "
- "saw this message. Thank you.\n");
- goto failed_reading_mft_data;
- }
- /* Process attribute description. */
- mftno2 = NTFS_GETU32(alist2 + 0x10);
- if (mftno2 != ino->i_number && mftno2 != last_mft2) {
- last_mft2 = mftno2;
- error2 = ntfs_read_mft_record(ino->vol, mftno2, mft2);
- if (error2) {
- ntfs_debug(DEBUG_FILE3, "parse_attributes: "
- "ntfs_read_mft_record(mftno2 = 0x%x) "
- "failed\n", mftno2);
- ntfs_free(mft2);
- goto failed_reading_mft_data;
- }
- }
- attr2 = ntfs_find_attr_in_mft_rec(
- ino->vol, /* ntfs volume */
- mftno2 == ino->i_number ?/* mft record is: */
- ino->attr: /* base record */
- mft2, /* extension record */
- NTFS_GETU32(alist2 + 0), /* type */
- (wchar_t*)(alist2 + alist2[7]), /* name */
- alist2[6], /* name length */
- 1, /* ignore case */
- NTFS_GETU16(alist2 + 24) /* instance number */
- );
- if (!attr2) {
- ntfs_error("parse_attributes: mft records 0x%x and/or "
- "0x%x corrupt!\n", ino->i_number,
- mftno2);
- ntfs_free(mft2);
- goto failed_reading_mft_data;
- }
- error2 = ntfs_insert_mft_attribute(ino, mftno2, attr2);
- if (error2) {
- ntfs_debug(DEBUG_FILE3, "parse_attributes: "
- "ntfs_insert_mft_attribute(mftno2 0x%x, "
- "attribute2 type 0x%x) failed\n", mftno2,
- NTFS_GETU32(alist2 + 0));
- ntfs_free(mft2);
- goto failed_reading_mft_data;
- }
- len2 -= l;
- alist2 += l;
- found2 = 1;
- }
- ntfs_free(mft2);
- tries = 1;
- goto continue_after_loading_mft_data;
-}
-}
-
-static void ntfs_load_attributes(ntfs_inode *ino)
-{
- ntfs_attribute *alist;
- int datasize;
- int offset, len, delta;
- char *buf;
- ntfs_volume *vol = ino->vol;
-
- ntfs_debug(DEBUG_FILE2, "load_attributes 0x%x 1\n", ino->i_number);
- if (ntfs_insert_mft_attributes(ino, ino->attr, ino->i_number))
- return;
- ntfs_debug(DEBUG_FILE2, "load_attributes 0x%x 2\n", ino->i_number);
- alist = ntfs_find_attr(ino, vol->at_attribute_list, 0);
- ntfs_debug(DEBUG_FILE2, "load_attributes 0x%x 3\n", ino->i_number);
- if (!alist)
- return;
- ntfs_debug(DEBUG_FILE2, "load_attributes 0x%x 4\n", ino->i_number);
- datasize = alist->size;
- ntfs_debug(DEBUG_FILE2, "load_attributes 0x%x: alist->size = 0x%x\n",
- ino->i_number, alist->size);
- if (alist->resident) {
- parse_attributes(ino, alist->d.data, &datasize);
- return;
- }
- ntfs_debug(DEBUG_FILE2, "load_attributes 0x%x 5\n", ino->i_number);
- buf = ntfs_malloc(1024);
- if (!buf) /* FIXME: Should be passing error code to caller. (AIA) */
- return;
- delta = 0;
- for (offset = 0; datasize; datasize -= len, offset += len) {
- ntfs_io io;
-
- io.fn_put = ntfs_put;
- io.fn_get = 0;
- io.param = buf + delta;
- len = 1024 - delta;
- if (len > datasize)
- len = datasize;
- ntfs_debug(DEBUG_FILE2, "load_attributes 0x%x: len = %i\n",
- ino->i_number, len);
- ntfs_debug(DEBUG_FILE2, "load_attributes 0x%x: delta = %i\n",
- ino->i_number, delta);
- io.size = len;
- if (ntfs_read_attr(ino, vol->at_attribute_list, 0, offset,
- &io))
- ntfs_error("error in load_attributes\n");
- delta += len;
- ntfs_debug(DEBUG_FILE2, "load_attributes 0x%x: after += len, "
- "delta = %i\n", ino->i_number, delta);
- parse_attributes(ino, buf, &delta);
- ntfs_debug(DEBUG_FILE2, "load_attributes 0x%x: after "
- "parse_attr, delta = %i\n", ino->i_number,
- delta);
- if (delta)
- /* Move remaining bytes to buffer start. */
- ntfs_memmove(buf, buf + len - delta, delta);
- }
- ntfs_debug(DEBUG_FILE2, "load_attributes 0x%x 6\n", ino->i_number);
- ntfs_free(buf);
-}
-
-int ntfs_init_inode(ntfs_inode *ino, ntfs_volume *vol, int inum)
-{
- char *buf;
- int error;
-
- ntfs_debug(DEBUG_FILE1, "Initializing inode 0x%x\n", inum);
- ino->i_number = inum;
- ino->vol = vol;
- ino->attr = buf = ntfs_malloc(vol->mft_record_size);
- if (!buf)
- return -ENOMEM;
- error = ntfs_read_mft_record(vol, inum, ino->attr);
- if (error) {
- ntfs_debug(DEBUG_OTHER, "Init inode: 0x%x failed\n", inum);
- return error;
- }
- ntfs_debug(DEBUG_FILE2, "Init inode: got mft 0x%x\n", inum);
- ino->sequence_number = NTFS_GETU16(buf + 0x10);
- ino->attr_count = 0;
- ino->record_count = 0;
- ino->records = 0;
- ino->attrs = 0;
- ntfs_load_attributes(ino);
- ntfs_debug(DEBUG_FILE2, "Init inode: done 0x%x\n", inum);
- return 0;
-}
-
-void ntfs_clear_inode(ntfs_inode *ino)
-{
- int i;
- if (!ino->attr) {
- ntfs_error("ntfs_clear_inode: double free\n");
- return;
- }
- ntfs_free(ino->attr);
- ino->attr = 0;
- ntfs_free(ino->records);
- ino->records = 0;
- for (i = 0; i < ino->attr_count; i++) {
- if (ino->attrs[i].name)
- ntfs_free(ino->attrs[i].name);
- if (ino->attrs[i].resident) {
- if (ino->attrs[i].d.data)
- ntfs_free(ino->attrs[i].d.data);
- } else {
- if (ino->attrs[i].d.r.runlist)
- ntfs_vfree(ino->attrs[i].d.r.runlist);
- }
- }
- ntfs_free(ino->attrs);
- ino->attrs = 0;
-}
-
-/* Check and fixup a MFT record. */
-int ntfs_check_mft_record(ntfs_volume *vol, char *record)
-{
- return ntfs_fixup_record(record, "FILE", vol->mft_record_size);
-}
-
-/* Return (in result) the value indicating the next available attribute
- * chunk number. Works for inodes w/o extension records only. */
-int ntfs_allocate_attr_number(ntfs_inode *ino, int *result)
-{
- if (ino->record_count != 1)
- return -EOPNOTSUPP;
- *result = NTFS_GETU16(ino->attr + 0x28);
- NTFS_PUTU16(ino->attr + 0x28, (*result) + 1);
- return 0;
-}
-
-/* Find the location of an attribute in the inode. A name of NULL indicates
- * unnamed attributes. Return pointer to attribute or NULL if not found. */
-char *ntfs_get_attr(ntfs_inode *ino, int attr, char *name)
-{
- /* Location of first attribute. */
- char *it = ino->attr + NTFS_GETU16(ino->attr + 0x14);
- int type;
- int len;
-
- /* Only check for magic DWORD here, fixup should have happened before.*/
- if (!IS_MFT_RECORD(ino->attr))
- return 0;
- do {
- type = NTFS_GETU32(it);
- len = NTFS_GETU16(it + 4);
- /* We found the attribute type. Is the name correct, too? */
- if (type == attr) {
- int namelen = NTFS_GETU8(it + 9);
- char *name_it, *n = name;
- /* Match given name and attribute name if present.
- Make sure attribute name is Unicode. */
- if (!name) {
- goto check_namelen;
- } else if (namelen) {
- for (name_it = it + NTFS_GETU16(it + 10);
- namelen; n++, name_it += 2, namelen--)
- if (*name_it != *n || name_it[1])
- break;
-check_namelen:
- if (!namelen)
- break;
- }
- }
- it += len;
- } while (type != -1); /* List of attributes ends with type -1. */
- if (type == -1)
- return 0;
- return it;
-}
-
-__s64 ntfs_get_attr_size(ntfs_inode *ino, int type, char *name)
-{
- ntfs_attribute *attr = ntfs_find_attr(ino, type, name);
- if (!attr)
- return 0;
- return
- attr->size;
-}
-
-int ntfs_attr_is_resident(ntfs_inode *ino, int type, char *name)
-{
- ntfs_attribute *attr = ntfs_find_attr(ino, type, name);
- if (!attr)
- return 0;
- return attr->resident;
-}
-
-/*
- * A run is coded as a type indicator, an unsigned length, and a signed cluster
- * offset.
- * . To save space, length and offset are fields of variable length. The low
- * nibble of the type indicates the width of the length :), the high nibble
- * the width of the offset.
- * . The first offset is relative to cluster 0, later offsets are relative to
- * the previous cluster.
- *
- * This function decodes a run. Length is an output parameter, data and cluster
- * are in/out parameters.
- */
-int ntfs_decompress_run(unsigned char **data, int *length,
- ntfs_cluster_t *cluster, int *ctype)
-{
- unsigned char type = *(*data)++;
- *ctype = 0;
- switch (type & 0xF) {
- case 1:
- *length = NTFS_GETS8(*data);
- break;
- case 2:
- *length = NTFS_GETS16(*data);
- break;
- case 3:
- *length = NTFS_GETS24(*data);
- break;
- case 4:
- *length = NTFS_GETS32(*data);
- break;
- /* Note: cases 5-8 are probably pointless to code, since how
- * many runs > 4GB of length are there? At the most, cases 5
- * and 6 are probably necessary, and would also require making
- * length 64-bit throughout. */
- default:
- ntfs_error("Can't decode run type field 0x%x\n", type);
- return -1;
- }
-// ntfs_debug(DEBUG_FILE3, "ntfs_decompress_run: length = 0x%x\n",*length);
- if (*length < 0)
- {
- ntfs_error("Negative run length decoded\n");
- return -1;
- }
- *data += (type & 0xF);
- switch (type & 0xF0) {
- case 0:
- *ctype = 2;
- break;
- case 0x10:
- *cluster += NTFS_GETS8(*data);
- break;
- case 0x20:
- *cluster += NTFS_GETS16(*data);
- break;
- case 0x30:
- *cluster += NTFS_GETS24(*data);
- break;
- case 0x40:
- *cluster += NTFS_GETS32(*data);
- break;
-#if 0 /* Keep for future, in case ntfs_cluster_t ever becomes 64bit. */
- case 0x50:
- *cluster += NTFS_GETS40(*data);
- break;
- case 0x60:
- *cluster += NTFS_GETS48(*data);
- break;
- case 0x70:
- *cluster += NTFS_GETS56(*data);
- break;
- case 0x80:
- *cluster += NTFS_GETS64(*data);
- break;
-#endif
- default:
- ntfs_error("Can't decode run type field 0x%x\n", type);
- return -1;
- }
-// ntfs_debug(DEBUG_FILE3, "ntfs_decompress_run: cluster = 0x%x\n",
-// *cluster);
- *data += (type >> 4);
- return 0;
-}
-
-static void dump_runlist(const ntfs_runlist *rl, const int rlen);
-
-/*
- * FIXME: ntfs_readwrite_attr() has the effect of writing @dest to @offset of
- * the attribute value of the attribute @attr in the in memory inode @ino.
- * If the attribute value of @attr is non-resident the value's contents at
- * @offset are actually written to disk (from @dest). The on disk mft record
- * describing the non-resident attribute value is not updated!
- * If the attribute value is resident then the value is written only in
- * memory. The on disk mft record containing the value is not written to disk.
- * A possible fix would be to call ntfs_update_inode() before returning. (AIA)
- */
-/* Reads l bytes of the attribute (attr, name) of ino starting at offset on
- * vol into buf. Returns the number of bytes read in the ntfs_io struct.
- * Returns 0 on success, errno on failure */
-int ntfs_readwrite_attr(ntfs_inode *ino, ntfs_attribute *attr, __s64 offset,
- ntfs_io *dest)
-{
- int rnum, s_vcn, error, clustersizebits;
- ntfs_cluster_t cluster, s_cluster, vcn, len;
- __s64 l, chunk, copied;
-
- ntfs_debug(DEBUG_FILE3, __FUNCTION__ "(): %s 0x%x bytes at offset "
- "0x%Lx %s inode 0x%x, attr type 0x%x.\n",
- dest->do_read ? "Read" : "Write", dest->size, offset,
- dest->do_read ? "from" : "to", ino->i_number,
- attr->type);
- l = dest->size;
- if (l == 0)
- return 0;
- if (dest->do_read) {
- /* If read _starts_ beyond end of stream, return nothing. */
- if (offset >= attr->size) {
- dest->size = 0;
- return 0;
- }
- /* If read _extends_ beyond end of stream, return as much
- * initialised data as we have. */
- if (offset + l >= attr->size)
- l = dest->size = attr->size - offset;
- } else {
- /*
- * If write extends beyond _allocated_ size, extend attribute,
- * updating attr->allocated and attr->size in the process. (AIA)
- */
- if ((!attr->resident && offset + l > attr->allocated) ||
- (attr->resident && offset + l > attr->size)) {
- error = ntfs_resize_attr(ino, attr, offset + l);
- if (error)
- return error;
- }
- if (!attr->resident) {
- /* Has amount of data increased? */
- if (offset + l > attr->size)
- attr->size = offset + l;
- /* Has amount of initialised data increased? */
- if (offset + l > attr->initialized) {
- /* FIXME: Clear the section between the old
- * initialised length and the write start.
- * (AIA) */
- attr->initialized = offset + l;
- }
- }
- }
- if (attr->resident) {
- if (dest->do_read)
- dest->fn_put(dest, (ntfs_u8*)attr->d.data + offset, l);
- else
- dest->fn_get((ntfs_u8*)attr->d.data + offset, dest, l);
- dest->size = l;
- return 0;
- }
- if (dest->do_read) {
- /* Read uninitialized data. */
- if (offset >= attr->initialized)
- return ntfs_read_zero(dest, l);
- if (offset + l > attr->initialized) {
- dest->size = chunk = attr->initialized - offset;
- error = ntfs_readwrite_attr(ino, attr, offset, dest);
- if (error || (dest->size != chunk && (error = -EIO, 1)))
- return error;
- dest->size += l - chunk;
- return ntfs_read_zero(dest, l - chunk);
- }
- if (attr->flags & ATTR_IS_COMPRESSED)
- return ntfs_read_compressed(ino, attr, offset, dest);
- } else {
- if (attr->flags & ATTR_IS_COMPRESSED)
- return ntfs_write_compressed(ino, attr, offset, dest);
- }
- vcn = 0;
- clustersizebits = ino->vol->cluster_size_bits;
- s_vcn = offset >> clustersizebits;
- for (rnum = 0; rnum < attr->d.r.len &&
- vcn + attr->d.r.runlist[rnum].len <= s_vcn; rnum++)
- vcn += attr->d.r.runlist[rnum].len;
- if (rnum == attr->d.r.len) {
- ntfs_debug(DEBUG_FILE3, __FUNCTION__ "(): EOPNOTSUPP: "
- "inode = 0x%x, rnum = %i, offset = 0x%Lx, vcn = 0x%x, "
- "s_vcn = 0x%x.\n", ino->i_number, rnum, offset, vcn,
- s_vcn);
- dump_runlist(attr->d.r.runlist, attr->d.r.len);
- /*FIXME: Should extend runlist. */
- return -EOPNOTSUPP;
- }
- copied = 0;
- while (l) {
- s_vcn = offset >> clustersizebits;
- cluster = attr->d.r.runlist[rnum].lcn;
- len = attr->d.r.runlist[rnum].len;
- s_cluster = cluster + s_vcn - vcn;
- chunk = ((__s64)(vcn + len) << clustersizebits) - offset;
- if (chunk > l)
- chunk = l;
- dest->size = chunk;
- error = ntfs_getput_clusters(ino->vol, s_cluster, offset -
- ((__s64)s_vcn << clustersizebits), dest);
- if (error) {
- ntfs_error("Read/write error.\n");
- dest->size = copied;
- return error;
- }
- l -= chunk;
- copied += chunk;
- offset += chunk;
- if (l && offset >= ((__s64)(vcn + len) << clustersizebits)) {
- rnum++;
- vcn += len;
- cluster = attr->d.r.runlist[rnum].lcn;
- len = attr->d.r.runlist[rnum].len;
- }
- }
- dest->size = copied;
- return 0;
-}
-
-int ntfs_read_attr(ntfs_inode *ino, int type, char *name, __s64 offset,
- ntfs_io *buf)
-{
- ntfs_attribute *attr;
-
- buf->do_read = 1;
- attr = ntfs_find_attr(ino, type, name);
- if (!attr) {
- ntfs_debug(DEBUG_FILE3, __FUNCTION__ "(): attr 0x%x not found "
- "in inode 0x%x\n", type, ino->i_number);
- return -EINVAL;
- }
- return ntfs_readwrite_attr(ino, attr, offset, buf);
-}
-
-int ntfs_write_attr(ntfs_inode *ino, int type, char *name, __s64 offset,
- ntfs_io *buf)
-{
- ntfs_attribute *attr;
-
- buf->do_read = 0;
- attr = ntfs_find_attr(ino, type, name);
- if (!attr) {
- ntfs_debug(DEBUG_FILE3, __FUNCTION__ "(): attr 0x%x not found "
- "in inode 0x%x\n", type, ino->i_number);
- return -EINVAL;
- }
- return ntfs_readwrite_attr(ino, attr, offset, buf);
-}
-
-/* -2 = error, -1 = hole, >= 0 means real disk cluster (lcn). */
-int ntfs_vcn_to_lcn(ntfs_inode *ino, int vcn)
-{
- int rnum;
- ntfs_attribute *data;
-
- data = ntfs_find_attr(ino, ino->vol->at_data, 0);
- if (!data || data->resident || data->flags & (ATTR_IS_COMPRESSED |
- ATTR_IS_ENCRYPTED))
- return -2;
- if (data->size <= (__s64)vcn << ino->vol->cluster_size_bits)
- return -2;
- if (data->initialized <= (__s64)vcn << ino->vol->cluster_size_bits)
- return -1;
- for (rnum = 0; rnum < data->d.r.len &&
- vcn >= data->d.r.runlist[rnum].len; rnum++)
- vcn -= data->d.r.runlist[rnum].len;
- if (data->d.r.runlist[rnum].lcn >= 0)
- return data->d.r.runlist[rnum].lcn + vcn;
- return data->d.r.runlist[rnum].lcn + vcn;
-}
-
-static int allocate_store(ntfs_volume *vol, ntfs_disk_inode *store, int count)
-{
- int i;
-
- if (store->count > count)
- return 0;
- if (store->size < count) {
- ntfs_mft_record *n = ntfs_malloc((count + 4) *
- sizeof(ntfs_mft_record));
- if (!n)
- return -ENOMEM;
- if (store->size) {
- for (i = 0; i < store->size; i++)
- n[i] = store->records[i];
- ntfs_free(store->records);
- }
- store->size = count + 4;
- store->records = n;
- }
- for (i = store->count; i < count; i++) {
- store->records[i].record = ntfs_malloc(vol->mft_record_size);
- if (!store->records[i].record)
- return -ENOMEM;
- store->count++;
- }
- return 0;
-}
-
-static void deallocate_store(ntfs_disk_inode* store)
-{
- int i;
-
- for (i = 0; i < store->count; i++)
- ntfs_free(store->records[i].record);
- ntfs_free(store->records);
- store->count = store->size = 0;
- store->records = 0;
-}
-
-/**
- * layout_runs - compress runlist into mapping pairs array
- * @attr: attribute containing the runlist to compress
- * @rec: destination buffer to hold the mapping pairs array
- * @offs: current position in @rec (in/out variable)
- * @size: size of the buffer @rec
- *
- * layout_runs walks the runlist in @attr, compresses it and writes it out the
- * resulting mapping pairs array into @rec (up to a maximum of @size bytes are
- * written). On entry @offs is the offset in @rec at which to begin writing the
- * mapping pairs array. On exit, it contains the offset in @rec of the first
- * byte after the end of the mapping pairs array.
- */
-static int layout_runs(ntfs_attribute *attr, char *rec, int *offs, int size)
-{
- int i, len, offset, coffs;
- /* ntfs_cluster_t MUST be signed! (AIA) */
- ntfs_cluster_t cluster, rclus;
- ntfs_runlist *rl = attr->d.r.runlist;
- cluster = 0;
- offset = *offs;
- for (i = 0; i < attr->d.r.len; i++) {
- /*
- * We cheat with this check on the basis that lcn will never
- * be less than -1 and the lcn delta will fit in signed
- * 32-bits (ntfs_cluster_t). (AIA)
- */
- if (rl[i].lcn < (ntfs_cluster_t)-1) {
- ntfs_error("layout_runs() encountered an out of bounds "
- "cluster delta, lcn = %i.\n",
- rl[i].lcn);
- return -ERANGE;
- }
- rclus = rl[i].lcn - cluster;
- len = rl[i].len;
- rec[offset] = 0;
- if (offset + 9 > size)
- return -E2BIG; /* It might still fit, but this
- * simplifies testing. */
- /*
- * Run length is stored as signed number, so deal with it
- * properly, i.e. observe that a negative number will have all
- * its most significant bits set to 1 but we don't store that
- * in the mapping pairs array. We store the smallest type of
- * negative number required, thus in the first if we check
- * whether len fits inside a signed byte and if so we store it
- * as such, the next ifs check for a signed short, then a signed
- * 24-bit and finally the full blown signed 32-bit. Same goes
- * for rlus below. (AIA)
- */
- if (len >= -0x80 && len <= 0x7f) {
- NTFS_PUTU8(rec + offset + 1, len & 0xff);
- coffs = 1;
- } else if (len >= -0x8000 && len <= 0x7fff) {
- NTFS_PUTU16(rec + offset + 1, len & 0xffff);
- coffs = 2;
- } else if (len >= -0x800000 && len <= 0x7fffff) {
- NTFS_PUTU24(rec + offset + 1, len & 0xffffff);
- coffs = 3;
- } else /* if (len >= -0x80000000LL && len <= 0x7fffffff */ {
- NTFS_PUTU32(rec + offset + 1, len);
- coffs = 4;
- } /* else ... FIXME: When len becomes 64-bit we need to extend
- * the else if () statements. (AIA) */
- *(rec + offset) |= coffs++;
- if (rl[i].lcn == (ntfs_cluster_t)-1) /* Compressed run. */
- /* Nothing */;
- else if (rclus >= -0x80 && rclus <= 0x7f) {
- *(rec + offset) |= 0x10;
- NTFS_PUTS8(rec + offset + coffs, rclus & 0xff);
- coffs += 1;
- } else if (rclus >= -0x8000 && rclus <= 0x7fff) {
- *(rec + offset) |= 0x20;
- NTFS_PUTS16(rec + offset + coffs, rclus & 0xffff);
- coffs += 2;
- } else if (rclus >= -0x800000 && rclus <= 0x7fffff) {
- *(rec + offset) |= 0x30;
- NTFS_PUTS24(rec + offset + coffs, rclus & 0xffffff);
- coffs += 3;
- } else /* if (rclus >= -0x80000000LL && rclus <= 0x7fffffff)*/ {
- *(rec + offset) |= 0x40;
- NTFS_PUTS32(rec + offset + coffs, rclus
- /* & 0xffffffffLL */);
- coffs += 4;
- } /* FIXME: When rclus becomes 64-bit.
- else if (rclus >= -0x8000000000 && rclus <= 0x7FFFFFFFFF) {
- *(rec + offset) |= 0x50;
- NTFS_PUTS40(rec + offset + coffs, rclus &
- 0xffffffffffLL);
- coffs += 5;
- } else if (rclus >= -0x800000000000 &&
- rclus <= 0x7FFFFFFFFFFF) {
- *(rec + offset) |= 0x60;
- NTFS_PUTS48(rec + offset + coffs, rclus &
- 0xffffffffffffLL);
- coffs += 6;
- } else if (rclus >= -0x80000000000000 &&
- rclus <= 0x7FFFFFFFFFFFFF) {
- *(rec + offset) |= 0x70;
- NTFS_PUTS56(rec + offset + coffs, rclus &
- 0xffffffffffffffLL);
- coffs += 7;
- } else {
- *(rec + offset) |= 0x80;
- NTFS_PUTS64(rec + offset + coffs, rclus);
- coffs += 8;
- } */
- offset += coffs;
- if (rl[i].lcn)
- cluster = rl[i].lcn;
- }
- if (offset >= size)
- return -E2BIG;
- /* Terminating null. */
- *(rec + offset++) = 0;
- *offs = offset;
- return 0;
-}
-
-static void count_runs(ntfs_attribute *attr, char *buf)
-{
- ntfs_u32 first, count, last, i;
-
- first = 0;
- for (i = 0, count = 0; i < attr->d.r.len; i++)
- count += attr->d.r.runlist[i].len;
- last = first + count - 1;
- NTFS_PUTU64(buf + 0x10, first);
- NTFS_PUTU64(buf + 0x18, last);
-}
-
-/**
- * layout_attr - convert in memory attribute to on disk attribute record
- * @attr: in memory attribute to convert
- * @buf: destination buffer for on disk attribute record
- * @size: size of the destination buffer
- * @psize: size of converted on disk attribute record (out variable)
- *
- * layout_attr() takes the attribute @attr and converts it into the appropriate
- * on disk structure, writing it into @buf (up to @size bytes are written).
- *
- * On success we return 0 and set @*psize to the actual byte size of the on-
- * disk attribute that was written into @buf.
- */
-static int layout_attr(ntfs_attribute *attr, char *buf, int size, int *psize)
-{
- int nameoff, hdrsize, asize;
-
- if (attr->resident) {
- nameoff = 0x18;
- hdrsize = (nameoff + 2 * attr->namelen + 7) & ~7;
- asize = (hdrsize + attr->size + 7) & ~7;
- if (size < asize)
- return -E2BIG;
- NTFS_PUTU32(buf + 0x10, attr->size);
- NTFS_PUTU8(buf + 0x16, attr->indexed);
- NTFS_PUTU16(buf + 0x14, hdrsize);
- if (attr->size)
- ntfs_memcpy(buf + hdrsize, attr->d.data, attr->size);
- } else {
- int error;
-
- if (attr->flags & ATTR_IS_COMPRESSED)
- nameoff = 0x48;
- else
- nameoff = 0x40;
- hdrsize = (nameoff + 2 * attr->namelen + 7) & ~7;
- if (size < hdrsize)
- return -E2BIG;
- /* Make asize point at the end of the attribute record header,
- i.e. at the beginning of the mapping pairs array. */
- asize = hdrsize;
- error = layout_runs(attr, buf, &asize, size);
- /* Now, asize points one byte beyond the end of the mapping
- pairs array. */
- if (error)
- return error;
- /* The next attribute has to begin on 8-byte boundary. */
- asize = (asize + 7) & ~7;
- /* FIXME: fragments */
- count_runs(attr, buf);
- NTFS_PUTU16(buf + 0x20, hdrsize);
- NTFS_PUTU16(buf + 0x22, attr->cengine);
- NTFS_PUTU32(buf + 0x24, 0);
- NTFS_PUTS64(buf + 0x28, attr->allocated);
- NTFS_PUTS64(buf + 0x30, attr->size);
- NTFS_PUTS64(buf + 0x38, attr->initialized);
- if (attr->flags & ATTR_IS_COMPRESSED)
- NTFS_PUTS64(buf + 0x40, attr->compsize);
- }
- NTFS_PUTU32(buf, attr->type);
- NTFS_PUTU32(buf + 4, asize);
- NTFS_PUTU8(buf + 8, attr->resident ? 0 : 1);
- NTFS_PUTU8(buf + 9, attr->namelen);
- NTFS_PUTU16(buf + 0xa, nameoff);
- NTFS_PUTU16(buf + 0xc, attr->flags);
- NTFS_PUTU16(buf + 0xe, attr->attrno);
- if (attr->namelen)
- ntfs_memcpy(buf + nameoff, attr->name, 2 * attr->namelen);
- *psize = asize;
- return 0;
-}
-
-/**
- * layout_inode - convert an in-memory inode into on disk mft record(s)
- * @ino: in memory inode to convert
- * @store: on disk inode, contain buffers for the on disk mft record(s)
- *
- * layout_inode takes the in memory inode @ino, converts it into a (sequence of)
- * mft record(s) and writes them to the appropriate buffers in the @store.
- *
- * Return 0 on success,
- * the required mft record count (>0) if the inode does not fit,
- * -ENOMEM if memory allocation problem, or
- * -EOPNOTSUP if beyond our capabilities.
- *
- * TODO: We at the moment do not support extension mft records. (AIA)
- */
-int layout_inode(ntfs_inode *ino, ntfs_disk_inode *store)
-{
- int offset, i, size, psize, error, count, recno;
- ntfs_attribute *attr;
- unsigned char *rec;
-
- error = allocate_store(ino->vol, store, ino->record_count);
- if (error)
- return error;
- size = ino->vol->mft_record_size;
- count = i = 0;
- do {
- if (count < ino->record_count) {
- recno = ino->records[count];
- } else {
- error = allocate_store(ino->vol, store, count + 1);
- if (error)
- return error;
- recno = -1;
- }
- /*
- * FIXME: We need to support extension records properly.
- * At the moment they wouldn't work. Probably would "just" get
- * corrupted if we write to them... (AIA)
- */
- store->records[count].recno = recno;
- rec = store->records[count].record;
- count++;
- /* Copy mft record header. */
- offset = NTFS_GETU16(ino->attr + 0x14); /* attrs_offset */
- ntfs_memcpy(rec, ino->attr, offset);
- /* Copy attributes. */
- while (i < ino->attr_count) {
- attr = ino->attrs + i;
- error = layout_attr(attr, rec + offset,
- size - offset - 8, &psize);
- if (error == -E2BIG && offset != NTFS_GETU16(ino->attr
- + 0x14))
- break;
- if (error)
- return error;
- offset += psize;
- i++;
- }
- /* Terminating attribute. */
- NTFS_PUTU32(rec + offset, 0xFFFFFFFF);
- offset += 4;
- NTFS_PUTU32(rec + offset, 0);
- offset += 4;
- NTFS_PUTU32(rec + 0x18, offset);
- } while (i < ino->attr_count || count < ino->record_count);
- return count - ino->record_count;
-}
-
-/*
- * FIXME: ntfs_update_inode() calls layout_inode() to create the mft record on
- * disk structure corresponding to the inode @ino. After that, ntfs_write_attr()
- * is called to write out the created mft record to disk.
- * We shouldn't need to re-layout every single time we are updating an mft
- * record. No wonder the ntfs driver is slow like hell. (AIA)
- */
-int ntfs_update_inode(ntfs_inode *ino)
-{
- int error, i;
- ntfs_disk_inode store;
- ntfs_io io;
-
- ntfs_bzero(&store, sizeof(store));
- error = layout_inode(ino, &store);
- if (error == -E2BIG) {
- i = ntfs_split_indexroot(ino);
- if (i != -ENOTDIR) {
- if (!i)
- i = layout_inode(ino, &store);
- error = i;
- }
- }
- if (error == -E2BIG) {
- error = ntfs_attr_allnonresident(ino);
- if (!error)
- error = layout_inode(ino, &store);
- }
- if (error > 0) {
- /* FIXME: Introduce extension records. */
- error = -E2BIG;
- }
- if (error) {
- if (error == -E2BIG)
- ntfs_error("Cannot handle saving inode 0x%x.\n",
- ino->i_number);
- deallocate_store(&store);
- return error;
- }
- io.fn_get = ntfs_get;
- io.fn_put = 0;
- for (i = 0; i < store.count; i++) {
- error = ntfs_insert_fixups(store.records[i].record,
- ino->vol->mft_record_size);
- if (error) {
- printk(KERN_ALERT "NTFS: ntfs_update_inode() caught "
- "corrupt %s mtf record ntfs record "
- "header. Refusing to write corrupt "
- "data to disk. Unmount and run chkdsk "
- "immediately!\n", i ? "extension":
- "base");
- deallocate_store(&store);
- return -EIO;
- }
- io.param = store.records[i].record;
- io.size = ino->vol->mft_record_size;
- error = ntfs_write_attr(ino->vol->mft_ino, ino->vol->at_data,
- 0, (__s64)store.records[i].recno <<
- ino->vol->mft_record_size_bits, &io);
- if (error || io.size != ino->vol->mft_record_size) {
- /* Big trouble, partially written file. */
- ntfs_error("Please unmount: Write error in inode "
- "0x%x\n", ino->i_number);
- deallocate_store(&store);
- return error ? error : -EIO;
- }
- }
- deallocate_store(&store);
- return 0;
-}
-
-void ntfs_decompress(unsigned char *dest, unsigned char *src, ntfs_size_t l)
-{
- int head, comp;
- int copied = 0;
- unsigned char *stop;
- int bits;
- int tag = 0;
- int clear_pos;
-
- while (1) {
- head = NTFS_GETU16(src) & 0xFFF;
- /* High bit indicates that compression was performed. */
- comp = NTFS_GETU16(src) & 0x8000;
- src += 2;
- stop = src + head;
- bits = 0;
- clear_pos = 0;
- if (head == 0)
- /* Block is not used. */
- return;/* FIXME: copied */
- if (!comp) { /* uncompressible */
- ntfs_memcpy(dest, src, 0x1000);
- dest += 0x1000;
- copied += 0x1000;
- src += 0x1000;
- if (l == copied)
- return;
- continue;
- }
- while (src <= stop) {
- if (clear_pos > 4096) {
- ntfs_error("Error 1 in decompress\n");
- return;
- }
- if (!bits) {
- tag = NTFS_GETU8(src);
- bits = 8;
- src++;
- if (src > stop)
- break;
- }
- if (tag & 1) {
- int i, len, delta, code, lmask, dshift;
- code = NTFS_GETU16(src);
- src += 2;
- if (!clear_pos) {
- ntfs_error("Error 2 in decompress\n");
- return;
- }
- for (i = clear_pos - 1, lmask = 0xFFF,
- dshift = 12; i >= 0x10; i >>= 1) {
- lmask >>= 1;
- dshift--;
- }
- delta = code >> dshift;
- len = (code & lmask) + 3;
- for (i = 0; i < len; i++) {
- dest[clear_pos] = dest[clear_pos -
- delta - 1];
- clear_pos++;
- copied++;
- if (copied==l)
- return;
- }
- } else {
- dest[clear_pos++] = NTFS_GETU8(src);
- src++;
- copied++;
- if (copied==l)
- return;
- }
- tag >>= 1;
- bits--;
- }
- dest += clear_pos;
- }
-}
-
-/*
- * NOTE: Neither of the ntfs_*_bit functions are atomic! But we don't need
- * them atomic at present as we never operate on shared/cached bitmaps.
- */
-static __inline__ int ntfs_test_bit(unsigned char *byte, const int bit)
-{
- return byte[bit >> 3] & (1 << (bit & 7)) ? 1 : 0;
-}
-
-static __inline__ void ntfs_set_bit(unsigned char *byte, const int bit)
-{
- byte[bit >> 3] |= 1 << (bit & 7);
-}
-
-static __inline__ void ntfs_clear_bit(unsigned char *byte, const int bit)
-{
- byte[bit >> 3] &= ~(1 << (bit & 7));
-}
-
-static __inline__ int ntfs_test_and_clear_bit(unsigned char *byte,
- const int bit)
-{
- unsigned char *ptr = byte + (bit >> 3);
- int b = 1 << (bit & 7);
- int oldbit = *ptr & b ? 1 : 0;
- *ptr &= ~b;
- return oldbit;
-}
-
-static void dump_runlist(const ntfs_runlist *rl, const int rlen)
-{
-#ifdef DEBUG
- int i;
- ntfs_cluster_t ct;
-
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): rlen = %i.\n", rlen);
- ntfs_debug(DEBUG_OTHER, "VCN LCN Run length\n");
- for (i = 0, ct = 0; i < rlen; ct += rl[i++].len) {
- if (rl[i].lcn == (ntfs_cluster_t)-1)
- ntfs_debug(DEBUG_OTHER, "0x%-8x LCN_HOLE 0x%-8x "
- "(%s)\n", ct, rl[i].len, rl[i].len ?
- "sparse run" : "run list end");
- else
- ntfs_debug(DEBUG_OTHER, "0x%-8x 0x%-8x 0x%-8x%s\n", ct,
- rl[i].lcn, rl[i].len, rl[i].len &&
- i + 1 < rlen ? "" : " (run list end)");
- if (!rl[i].len)
- break;
- }
-#endif
-}
-
-/**
- * splice_runlists - splice two run lists into one
- * @rl1: pointer to address of first run list
- * @r1len: number of elementfs in first run list
- * @rl2: pointer to second run list
- * @r2len: number of elements in second run list
- *
- * Append the run list @rl2 to the run list *@rl1 and return the result in
- * *@rl1 and *@r1len.
- *
- * Return 0 on success or -errno on error, in which case *@rl1 and *@r1len are
- * left untouched.
- *
- * The only possible error code at the moment is -ENOMEM and only happens if
- * there is insufficient memory to allocate the new run list (only happens
- * when size of (rl1 + rl2) > allocated size of rl1).
- */
-int splice_runlists(ntfs_runlist **rl1, int *r1len, const ntfs_runlist *rl2,
- int r2len)
-{
- ntfs_runlist *rl;
- int rlen, rl_size, rl2_pos;
-
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Entering with *r1len = %i, "
- "r2len = %i.\n", *r1len, r2len);
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Dumping 1st runlist.\n");
- if (*rl1)
- dump_runlist(*rl1, *r1len);
- else
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Not present.\n");
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Dumping 2nd runlist.\n");
- dump_runlist(rl2, r2len);
- rlen = *r1len + r2len + 1;
- rl_size = (rlen * sizeof(ntfs_runlist) + PAGE_SIZE - 1) &
- PAGE_MASK;
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): rlen = %i, rl_size = %i.\n",
- rlen, rl_size);
- /* Do we have enough space? */
- if (rl_size <= ((*r1len * sizeof(ntfs_runlist) + PAGE_SIZE - 1) &
- PAGE_MASK)) {
- /* Have enough space already. */
- rl = *rl1;
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Have enough space "
- "already.\n");
- } else {
- /* Need more space. Reallocate. */
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Need more space.\n");
- rl = ntfs_vmalloc(rlen << sizeof(ntfs_runlist));
- if (!rl)
- return -ENOMEM;
- /* Copy over rl1. */
- ntfs_memcpy(rl, *rl1, *r1len * sizeof(ntfs_runlist));
- ntfs_vfree(*rl1);
- *rl1 = rl;
- }
- /* Reuse rl_size as the current position index into rl. */
- rl_size = *r1len - 1;
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): rl_size = %i.\n");
- /* Coalesce neighbouring elements, if present. */
- rl2_pos = 0;
- if (rl[rl_size].lcn + rl[rl_size].len == rl2[rl2_pos].lcn) {
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Coalescing adjacent "
- "runs.\n");
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Before: "
- "rl[rl_size].len = %i.\n", rl[rl_size].len);
- rl[rl_size].len += rl2[rl2_pos].len;
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): After: "
- "rl[rl_size].len = %i.\n", rl[rl_size].len);
- rl2_pos++;
- r2len--;
- rlen--;
- }
- rl_size++;
- /* Copy over rl2. */
- ntfs_memcpy(rl + rl_size, rl2 + rl2_pos, r2len * sizeof(ntfs_runlist));
- rlen--;
- rl[rlen].lcn = (ntfs_cluster_t)-1;
- rl[rlen].len = (ntfs_cluster_t)0;
- *r1len = rlen;
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Dumping result runlist.\n");
- dump_runlist(*rl1, *r1len);
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Returning with *r1len = "
- "%i.\n", rlen);
- return 0;
-}
-
-/**
- * ntfs_alloc_mft_record - allocate an mft record
- * @vol: volume to allocate an mft record on
- * @result: the mft record number allocated
- *
- * Allocate a new mft record on disk. Return 0 on success or -ERRNO on error.
- * On success, *@result contains the allocated mft record number. On error,
- * *@result is -1UL.
- *
- * Note, this function doesn't actually set the mft record to be in use. This
- * is done by the caller, which at the moment is only ntfs_alloc_inode().
- *
- * To find a free mft record, we scan the mft bitmap for a zero bit. To
- * optimize this we start scanning at the place where we last stopped and we
- * perform wrap around when we reach the end. Note, we do not try to allocate
- * mft records below number 24 because numbers 0 to 15 are the defined system
- * files anyway and 16 to 24 are special in that they are used for storing
- * extension mft records for $MFT's $DATA attribute. This is required to avoid
- * the possibility of creating a run list with a circular dependence which once
- * written to disk can never be read in again. Windows will only use records
- * 16 to 24 for normal files if the volume is completely out of space. We never
- * use them which means that when the volume is really out of space we cannot
- * create any more files while Windows can still create up to 8 small files. We
- * can start doing this at some later time, doesn't matter much for now.
- *
- * When scanning the mft bitmap, we only search up to the last allocated mft
- * record. If there are no free records left in the range 24 to number of
- * allocated mft records, then we extend the mft data in order to create free
- * mft records. We extend the allocated size of $MFT/$DATA by 16 records at a
- * time or one cluster, if cluster size is above 16kiB. If there isn't
- * sufficient space to do this, we try to extend by a single mft record or one
- * cluster, if cluster size is above mft record size, but we only do this if
- * there is enough free space, which we know from the values returned by the
- * failed cluster allocation function when we tried to do the first allocation.
- *
- * No matter how many mft records we allocate, we initialize only the first
- * allocated mft record (incrementing mft data size and initialized size) and
- * return its number to the caller in @*result, unless there are less than 24
- * mft records, in which case we allocate and initialize mft records until we
- * reach record 24 which we consider as the first free mft record for use by
- * normal files.
- *
- * If during any stage we overflow the initialized data in the mft bitmap, we
- * extend the initialized size (and data size) by 8 bytes, allocating another
- * cluster if required. The bitmap data size has to be at least equal to the
- * number of mft records in the mft, but it can be bigger, in which case the
- * superflous bits are padded with zeroes.
- *
- * Thus, when we return successfully (return value 0), we will have:
- * - initialized / extended the mft bitmap if necessary,
- * - initialized / extended the mft data if necessary,
- * - set the bit corresponding to the mft record being allocated in the
- * mft bitmap, and we will
- * - return the mft record number in @*result.
- *
- * On error (return value below zero), nothing will have changed. If we had
- * changed anything before the error occured, we will have reverted back to
- * the starting state before returning to the caller. Thus, except for bugs,
- * we should always leave the volume in a consitents state when returning from
- * this function. NOTE: Small exception to this is that we set the bit in the
- * mft bitmap but we do not mark the mft record in use, which is inconsistent.
- * However, the caller will immediately add the wanted attributes to the mft
- * record, set it in use and write it out to disk, so there should be no
- * problem.
- *
- * Note, this function cannot make use of most of the normal functions, like
- * for example for attribute resizing, etc, because when the run list overflows
- * the base mft record and an attribute list is used, it is very important
- * that the extension mft records used to store the $DATA attribute of $MFT
- * can be reached without having to read the information contained inside
- * them, as this would make it impossible to find them in the first place
- * after the volume is dismounted. $MFT/$BITMAP probably doesn't need to
- * follow this rule because the bitmap is not essential for finding the mft
- * records, but on the other hand, handling the bitmap in this special way
- * would make life easier because otherwise there might be circular invocations
- * of functions when reading the bitmap but if we are careful, we should be
- * able to avoid all problems.
- *
- * FIXME: Don't forget $MftMirr, though this probably belongs in
- * ntfs_update_inode() (or even deeper). (AIA)
- *
- * FIXME: Want finer grained locking. (AIA)
- */
-static int ntfs_alloc_mft_record(ntfs_volume *vol, unsigned long *result)
-{
- unsigned long nr_mft_records, buf_size, buf_pos, pass_start, pass_end;
- unsigned long last_read_pos, mft_rec_size, bit, l;
- ntfs_attribute *data, *bmp;
- __u8 *buf, *byte, pass, b, have_allocated_mftbmp = 0;
- int rlen, rl_size = 0, r2len, rl2_size, old_data_rlen, err = 0;
- ntfs_runlist *rl, *rl2;
- ntfs_cluster_t lcn = 0, old_data_len;
- ntfs_io io;
- __s64 ll, old_data_allocated, old_data_initialized, old_data_size;
-
- *result = -1UL;
- /* Allocate a buffer and setup the io structure. */
- buf = (__u8*)__get_free_page(GFP_NOFS);
- if (!buf)
- return -ENOMEM;
- lock_kernel();
- /* Get the $DATA and $BITMAP attributes of $MFT. */
- data = ntfs_find_attr(vol->mft_ino, vol->at_data, 0);
- bmp = ntfs_find_attr(vol->mft_ino, vol->at_bitmap, 0);
- if (!data || !bmp) {
- err = -EINVAL;
- goto err_ret;
- }
- /* Determine the number of allocated mft records in the mft. */
- pass_end = nr_mft_records = data->allocated >>
- vol->mft_record_size_bits;
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): nr_mft_records = %lu.\n",
- nr_mft_records);
- /* Make sure we don't overflow the bitmap. */
- l = bmp->initialized << 3;
- if (l < nr_mft_records)
- // FIXME: It might be a good idea to extend the bitmap instead.
- pass_end = l;
- pass = 1;
- buf_pos = vol->mft_data_pos;
- if (buf_pos >= pass_end) {
- buf_pos = 24UL;
- pass = 2;
- }
- pass_start = buf_pos;
- rl = bmp->d.r.runlist;
- rlen = bmp->d.r.len - 1;
- lcn = rl[rlen].lcn + rl[rlen].len;
- io.fn_put = ntfs_put;
- io.fn_get = ntfs_get;
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Starting bitmap search.\n");
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): pass = %i, pass_start = %lu, "
- "pass_end = %lu.\n", pass, pass_start, pass_end);
- byte = NULL; // FIXME: For debugging only.
- /* Loop until a free mft record is found. */
- io.size = (nr_mft_records >> 3) & ~PAGE_MASK;
- for (;; io.size = PAGE_SIZE) {
- io.param = buf;
- io.do_read = 1;
- last_read_pos = buf_pos >> 3;
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Before: "
- "bmp->allocated = 0x%Lx, bmp->size = 0x%Lx, "
- "bmp->initialized = 0x%Lx.\n", bmp->allocated,
- bmp->size, bmp->initialized);
- err = ntfs_readwrite_attr(vol->mft_ino, bmp, last_read_pos,
- &io);
- if (err)
- goto err_ret;
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Read %lu bytes.\n",
- (unsigned long)io.size);
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): After: "
- "bmp->allocated = 0x%Lx, bmp->size = 0x%Lx, "
- "bmp->initialized = 0x%Lx.\n", bmp->allocated,
- bmp->size, bmp->initialized);
- if (!io.size)
- goto pass_done;
- buf_size = io.size << 3;
- bit = buf_pos & 7UL;
- buf_pos &= ~7UL;
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Before loop: "
- "buf_size = %lu, buf_pos = %lu, bit = %lu, "
- "*byte = 0x%x, b = %u.\n",
- buf_size, buf_pos, bit, byte ? *byte : -1, b);
- for (; bit < buf_size && bit + buf_pos < pass_end;
- bit &= ~7UL, bit += 8UL) {
- byte = buf + (bit >> 3);
- if (*byte == 0xff)
- continue;
- b = ffz((unsigned long)*byte);
- if (b < (__u8)8 && b >= (bit & 7UL)) {
- bit = b + (bit & ~7UL) + buf_pos;
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): "
- "Found free rec in for loop. "
- "bit = %lu\n", bit);
- goto found_free_rec;
- }
- }
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): After loop: "
- "buf_size = %lu, buf_pos = %lu, bit = %lu, "
- "*byte = 0x%x, b = %u.\n",
- buf_size, buf_pos, bit, byte ? *byte : -1, b);
- buf_pos += buf_size;
- if (buf_pos < pass_end)
- continue;
-pass_done: /* Finished with the current pass. */
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): At pass_done.\n");
- if (pass == 1) {
- /*
- * Now do pass 2, scanning the first part of the zone
- * we omitted in pass 1.
- */
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Done pass "
- "1.\n");
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Pass = 2.\n");
- pass = 2;
- pass_end = pass_start;
- buf_pos = pass_start = 24UL;
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): pass = %i, "
- "pass_start = %lu, pass_end = %lu.\n",
- pass, pass_start, pass_end);
- continue;
- } /* pass == 2 */
- /* No free records left. */
- if (bmp->initialized << 3 > nr_mft_records &&
- bmp->initialized > 3) {
- /*
- * The mft bitmap is already bigger but the space is
- * not covered by mft records, this implies that the
- * next records are all free, so we already have found
- * a free record.
- */
- bit = nr_mft_records;
- if (bit < 24UL)
- bit = 24UL;
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Found free "
- "record bit (#1) = 0x%lx.\n", bit);
- goto found_free_rec;
- }
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Done pass 2.\n");
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Before: "
- "bmp->allocated = 0x%Lx, bmp->size = 0x%Lx, "
- "bmp->initialized = 0x%Lx.\n", bmp->allocated,
- bmp->size, bmp->initialized);
- /* Need to extend the mft bitmap. */
- if (bmp->initialized + 8LL > bmp->allocated) {
- ntfs_io io2;
-
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Initialized "
- "> allocated.\n");
- /* Need to extend bitmap by one more cluster. */
- rl = bmp->d.r.runlist;
- rlen = bmp->d.r.len - 1;
- lcn = rl[rlen].lcn + rl[rlen].len;
- io2.fn_put = ntfs_put;
- io2.fn_get = ntfs_get;
- io2.param = &b;
- io2.size = 1;
- io2.do_read = 1;
- err = ntfs_readwrite_attr(vol->bitmap, data, lcn >> 3,
- &io2);
- if (err)
- goto err_ret;
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Read %lu "
- "bytes.\n", (unsigned long)io2.size);
- if (io2.size == 1 && b != 0xff) {
- __u8 tb = 1 << (lcn & (ntfs_cluster_t)7);
- if (!(b & tb)) {
- /* Next cluster is free. Allocate it. */
- b |= tb;
- io2.param = &b;
- io2.do_read = 0;
- err = ntfs_readwrite_attr(vol->bitmap,
- data, lcn >> 3, &io2);
- if (err || io.size != 1) {
- if (!err)
- err = -EIO;
- goto err_ret;
- }
-append_mftbmp_simple: rl[rlen].len++;
- have_allocated_mftbmp |= 1;
- ntfs_debug(DEBUG_OTHER, __FUNCTION__
- "(): Appending one "
- "cluster to mftbmp.\n");
- }
- }
- if (!have_allocated_mftbmp) {
- /* Allocate a cluster from the DATA_ZONE. */
- ntfs_cluster_t lcn2 = lcn;
- ntfs_cluster_t count = 1;
- err = ntfs_allocate_clusters(vol, &lcn2,
- &count, &rl2, &r2len,
- DATA_ZONE);
- if (err)
- goto err_ret;
- if (count != 1 || lcn2 <= 0) {
- if (count > 0) {
-rl2_dealloc_err_out: if (ntfs_deallocate_clusters(
- vol, rl2, r2len))
- ntfs_error(__FUNCTION__
- "(): Cluster "
- "deallocation in error "
- "code path failed! You "
- "should run chkdsk.\n");
- }
- ntfs_vfree(rl2);
- if (!err)
- err = -EINVAL;
- goto err_ret;
- }
- if (lcn2 == lcn) {
- ntfs_vfree(rl2);
- goto append_mftbmp_simple;
- }
- /* We need to append a new run. */
- rl_size = (rlen * sizeof(ntfs_runlist) +
- PAGE_SIZE - 1) & PAGE_MASK;
- /* Reallocate memory if necessary. */
- if ((rlen + 2) * sizeof(ntfs_runlist) >=
- rl_size) {
- ntfs_runlist *rlt;
-
- rl_size += PAGE_SIZE;
- rlt = ntfs_vmalloc(rl_size);
- if (!rlt) {
- err = -ENOMEM;
- goto rl2_dealloc_err_out;
- }
- ntfs_memcpy(rlt, rl, rl_size -
- PAGE_SIZE);
- ntfs_vfree(rl);
- bmp->d.r.runlist = rl = rlt;
- }
- ntfs_vfree(rl2);
- rl[rlen].lcn = lcn = lcn2;
- rl[rlen].len = count;
- bmp->d.r.len = ++rlen;
- have_allocated_mftbmp |= 2;
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): "
- "Adding run to mftbmp. "
- "LCN = %i, len = %i\n", lcn,
- count);
- }
- /*
- * We now have extended the mft bitmap allocated size
- * by one cluster. Reflect this in the attribute.
- */
- bmp->allocated += (__s64)vol->cluster_size;
- }
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): After: "
- "bmp->allocated = 0x%Lx, bmp->size = 0x%Lx, "
- "bmp->initialized = 0x%Lx.\n", bmp->allocated,
- bmp->size, bmp->initialized);
- /* We now have sufficient allocated space. */
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Now have sufficient "
- "allocated space in mftbmp.\n");
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Before: "
- "bmp->allocated = 0x%Lx, bmp->size = 0x%Lx, "
- "bmp->initialized = 0x%Lx.\n", bmp->allocated,
- bmp->size, bmp->initialized);
- buf_pos = bmp->initialized;
- bmp->initialized += 8LL;
- if (bmp->initialized > bmp->size)
- bmp->size = bmp->initialized;
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): After: "
- "bmp->allocated = 0x%Lx, bmp->size = 0x%Lx, "
- "bmp->initialized = 0x%Lx.\n", bmp->allocated,
- bmp->size, bmp->initialized);
- have_allocated_mftbmp |= 4;
- /* Update the mft bitmap attribute value. */
- memset(buf, 0, 8);
- io.param = buf;
- io.size = 8;
- io.do_read = 0;
- err = ntfs_readwrite_attr(vol->mft_ino, bmp, buf_pos, &io);
- if (err || io.size != 8) {
- if (!err)
- err = -EIO;
- goto shrink_mftbmp_err_ret;
- }
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Wrote extended "
- "mftbmp bytes %lu.\n", (unsigned long)io.size);
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): After write: "
- "bmp->allocated = 0x%Lx, bmp->size = 0x%Lx, "
- "bmp->initialized = 0x%Lx.\n", bmp->allocated,
- bmp->size, bmp->initialized);
- bit = buf_pos << 3;
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Found free record "
- "bit (#2) = 0x%lx.\n", bit);
- goto found_free_rec;
- }
-found_free_rec:
- /* bit is the found free mft record. Allocate it in the mft bitmap. */
- vol->mft_data_pos = bit;
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): At found_free_rec.\n");
- io.param = buf;
- io.size = 1;
- io.do_read = 1;
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Before update: "
- "bmp->allocated = 0x%Lx, bmp->size = 0x%Lx, "
- "bmp->initialized = 0x%Lx.\n", bmp->allocated,
- bmp->size, bmp->initialized);
- err = ntfs_readwrite_attr(vol->mft_ino, bmp, bit >> 3, &io);
- if (err || io.size != 1) {
- if (!err)
- err = -EIO;
- goto shrink_mftbmp_err_ret;
- }
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Read %lu bytes.\n",
- (unsigned long)io.size);
-#ifdef DEBUG
- /* Check our bit is really zero! */
- if (*buf & (1 << (bit & 7)))
- BUG();
-#endif
- *buf |= 1 << (bit & 7);
- io.param = buf;
- io.do_read = 0;
- err = ntfs_readwrite_attr(vol->mft_ino, bmp, bit >> 3, &io);
- if (err || io.size != 1) {
- if (!err)
- err = -EIO;
- goto shrink_mftbmp_err_ret;
- }
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Wrote %lu bytes.\n",
- (unsigned long)io.size);
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): After update: "
- "bmp->allocated = 0x%Lx, bmp->size = 0x%Lx, "
- "bmp->initialized = 0x%Lx.\n", bmp->allocated,
- bmp->size, bmp->initialized);
- /* The mft bitmap is now uptodate. Deal with mft data attribute now. */
- ll = (__s64)(bit + 1) << vol->mft_record_size_bits;
- if (ll <= data->initialized) {
- /* The allocated record is already initialized. We are done! */
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Allocated mft record "
- "already initialized!\n");
- goto done_ret;
- }
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Allocated mft record needs "
- "to be initialized.\n");
- /* The mft record is outside the initialized data. */
- mft_rec_size = (unsigned long)vol->mft_record_size;
- /* Preserve old values for undo purposes. */
- old_data_allocated = data->allocated;
- old_data_rlen = data->d.r.len - 1;
- old_data_len = data->d.r.runlist[old_data_rlen].len;
- /*
- * If necessary, extend the mft until it covers the allocated record.
- * The loop is only actually used when a freshly formatted volume is
- * first written to. But it optimizes away nicely in the common case.
- */
- while (ll > data->allocated) {
- ntfs_cluster_t lcn2, nr_lcn2, nr, min_nr;
-
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Extending mft "
- "data allocation, data->allocated = 0x%Lx, "
- "data->size = 0x%Lx, data->initialized = "
- "0x%Lx.\n", data->allocated, data->size,
- data->initialized);
- /* Minimum allocation is one mft record worth of clusters. */
- if (mft_rec_size <= vol->cluster_size)
- min_nr = (ntfs_cluster_t)1;
- else
- min_nr = mft_rec_size >> vol->cluster_size_bits;
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): min_nr = %i.\n",
- min_nr);
- /* Allocate 16 mft records worth of clusters. */
- nr = mft_rec_size << 4 >> vol->cluster_size_bits;
- if (!nr)
- nr = (ntfs_cluster_t)1;
- /* Determine the preferred allocation location. */
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): nr = %i.\n", nr);
- rl2 = data->d.r.runlist;
- r2len = data->d.r.len;
- lcn2 = rl2[r2len - 1].lcn + rl2[r2len - 1].len;
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): rl2[r2len - 1].lcn "
- "= %i, .len = %i.\n", rl2[r2len - 1].lcn,
- rl2[r2len - 1].len);
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): lcn2 = %i, r2len = "
- "%i.\n", lcn2, r2len);
-retry_mft_data_allocation:
- nr_lcn2 = nr;
- err = ntfs_allocate_clusters(vol, &lcn2, &nr_lcn2, &rl2,
- &r2len, MFT_ZONE);
-#ifdef DEBUG
- if (!err && nr_lcn2 < min_nr)
- /* Allocated less than minimum needed. Weird! */
- BUG();
-#endif
- if (err) {
- /*
- * If there isn't enough space to do the wanted
- * allocation, but there is enough space to do a
- * minimal allocation, then try that, unless the wanted
- * allocation was already the minimal allocation.
- */
- if (err == -ENOSPC && nr > min_nr &&
- nr_lcn2 >= min_nr) {
- nr = min_nr;
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): "
- "Retrying mft data "
- "allocation, nr = min_nr = %i"
- ".\n", nr);
- goto retry_mft_data_allocation;
- }
- goto undo_mftbmp_alloc_err_ret;
- }
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Allocated %i "
- "clusters starting at LCN %i.\n", nr_lcn2,
- lcn2);
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Allocated "
- "runlist:\n");
- dump_runlist(rl2, r2len);
- /* Append rl2 to the mft data attribute's run list. */
- err = splice_runlists(&data->d.r.runlist, (int*)&data->d.r.len,
- rl2, r2len);
- if (err) {
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): "
- "splice_runlists failed with error "
- "code %i.\n", -err);
- goto undo_partial_data_alloc_err_ret;
- }
- /* Reflect the allocated clusters in the mft allocated data. */
- data->allocated += nr_lcn2 << vol->cluster_size_bits;
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): After extending mft "
- "data allocation, data->allocated = 0x%Lx, "
- "data->size = 0x%Lx, data->initialized = "
- "0x%Lx.\n", data->allocated, data->size,
- data->initialized);
- }
- /* Prepare a formatted (empty) mft record. */
- memset(buf, 0, mft_rec_size);
- ntfs_fill_mft_header(buf, mft_rec_size, 0, 0, 0);
- err = ntfs_insert_fixups(buf, mft_rec_size);
- if (err)
- goto undo_data_alloc_err_ret;
- /*
- * Extend mft data initialized size to reach the allocated mft record
- * and write the formatted mft record buffer to each mft record being
- * initialized. Note, that ntfs_readwrite_attr extends both
- * data->initialized and data->size, so no need for us to touch them.
- */
- old_data_initialized = data->initialized;
- old_data_size = data->size;
- while (ll > data->initialized) {
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Initializing mft "
- "record 0x%Lx.\n",
- data->initialized >> vol->mft_record_size_bits);
- io.param = buf;
- io.size = mft_rec_size;
- io.do_read = 0;
- err = ntfs_readwrite_attr(vol->mft_ino, data,
- data->initialized, &io);
- if (err || io.size != mft_rec_size) {
- if (!err)
- err = -EIO;
- goto undo_data_init_err_ret;
- }
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Wrote %i bytes to "
- "mft data.\n", io.size);
- }
- /* Update the VFS inode size as well. */
- VFS_I(vol->mft_ino)->i_size = data->size;
-#ifdef DEBUG
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): After mft record "
- "initialization: data->allocated = 0x%Lx, data->size "
- "= 0x%Lx, data->initialized = 0x%Lx.\n",
- data->allocated, data->size, data->initialized);
- /* Sanity checks. */
- if (data->size > data->allocated || data->size < data->initialized ||
- data->initialized > data->allocated)
- BUG();
-#endif
-done_ret:
- /* Return the number of the allocated mft record. */
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): At done_ret. *result = bit = "
- "0x%lx.\n", bit);
- *result = bit;
- vol->mft_data_pos = bit + 1;
-err_ret:
- unlock_kernel();
- free_page((unsigned long)buf);
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Syncing inode $MFT.\n");
- if (ntfs_update_inode(vol->mft_ino))
- ntfs_error(__FUNCTION__ "(): Failed to sync inode $MFT. "
- "Continuing anyway.\n");
- if (!err) {
- ntfs_debug(DEBUG_FILE3, __FUNCTION__ "(): Done. Allocated mft "
- "record number *result = 0x%lx.\n", *result);
- return 0;
- }
- if (err != -ENOSPC)
- ntfs_error(__FUNCTION__ "(): Failed to allocate an mft "
- "record. Returning error code %i.\n", -err);
- else
- ntfs_debug(DEBUG_FILE3, __FUNCTION__ "(): Failed to allocate "
- "an mft record due to lack of free space.\n");
- return err;
-undo_data_init_err_ret:
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): At "
- "undo_data_init_err_ret.\n");
- data->initialized = old_data_initialized;
- data->size = old_data_size;
-undo_data_alloc_err_ret:
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): At undo_data_alloc_err_ret."
- "\n");
- data->allocated = old_data_allocated;
-undo_partial_data_alloc_err_ret:
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): At "
- "undo_partial_data_alloc_err_ret.\n");
- /* Deallocate the clusters. */
- if (ntfs_deallocate_clusters(vol, rl2, r2len))
- ntfs_error(__FUNCTION__ "(): Error deallocating clusters in "
- "error code path. You should run chkdsk.\n");
- ntfs_vfree(rl2);
- /* Revert the run list back to what it was before. */
- r2len = data->d.r.len;
- rl2 = data->d.r.runlist;
- rl2[old_data_rlen++].len = old_data_len;
- rl2[old_data_rlen].lcn = (ntfs_cluster_t)-1;
- rl2[old_data_rlen].len = (ntfs_cluster_t)0;
- data->d.r.len = old_data_rlen;
- rl2_size = ((old_data_rlen + 1) * sizeof(ntfs_runlist) + PAGE_SIZE -
- 1) & PAGE_MASK;
- /* Reallocate memory freeing any extra memory allocated. */
- if (rl2_size < ((r2len * sizeof(ntfs_runlist) + PAGE_SIZE - 1) &
- PAGE_MASK)) {
- rl2 = ntfs_vmalloc(rl2_size);
- if (rl2) {
- ntfs_memcpy(rl2, data->d.r.runlist, rl2_size);
- ntfs_vfree(data->d.r.runlist);
- data->d.r.runlist = rl2;
- } else
- ntfs_error(__FUNCTION__ "(): Error reallocating "
- "memory in error code path. This "
- "should be harmless.\n");
- }
-undo_mftbmp_alloc_err_ret:
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): At "
- "undo_mftbmp_alloc_err_ret.\n");
- /* Deallocate the allocated bit in the mft bitmap. */
- io.param = buf;
- io.size = 1;
- io.do_read = 1;
- err = ntfs_readwrite_attr(vol->mft_ino, bmp, bit >> 3, &io);
- if (!err && io.size == 1) {
- *buf &= ~(1 << (bit & 7));
- io.param = buf;
- io.do_read = 0;
- err = ntfs_readwrite_attr(vol->mft_ino, bmp, bit >> 3, &io);
- }
- if (err || io.size != 1) {
- if (!err)
- err = -EIO;
- ntfs_error(__FUNCTION__ "(): Error deallocating mft record in "
- "error code path. You should run chkdsk.\n");
- }
-shrink_mftbmp_err_ret:
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): At shrink_mftbmp_err_ret.\n");
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): have_allocated_mftbmp = "
- "%i.\n", have_allocated_mftbmp);
- if (!have_allocated_mftbmp)
- goto err_ret;
- /* Shrink the mftbmp back to previous size. */
- if (bmp->size == bmp->initialized)
- bmp->size -= 8LL;
- bmp->initialized -= 8LL;
- have_allocated_mftbmp &= ~4;
- /* If no allocation occured then we are done. */
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): have_allocated_mftbmp = "
- "%i.\n", have_allocated_mftbmp);
- if (!have_allocated_mftbmp)
- goto err_ret;
- /* Deallocate the allocated cluster. */
- bmp->allocated -= (__s64)vol->cluster_size;
- if (ntfs_deallocate_cluster_run(vol, lcn, (ntfs_cluster_t)1))
- ntfs_error(__FUNCTION__ "(): Error deallocating cluster in "
- "error code path. You should run chkdsk.\n");
- switch (have_allocated_mftbmp & 3) {
- case 1:
- /* Delete the last lcn from the last run of mftbmp. */
- rl[rlen - 1].len--;
- break;
- case 2:
- /* Delete the last run of mftbmp. */
- bmp->d.r.len = --rlen;
- /* Reallocate memory if necessary. */
- if ((rlen + 1) * sizeof(ntfs_runlist) <= rl_size - PAGE_SIZE) {
- ntfs_runlist *rlt;
-
- rl_size -= PAGE_SIZE;
- rlt = ntfs_vmalloc(rl_size);
- if (rlt) {
- ntfs_memcpy(rlt, rl, rl_size);
- ntfs_vfree(rl);
- bmp->d.r.runlist = rl = rlt;
- } else
- ntfs_error(__FUNCTION__ "(): Error "
- "reallocating memory in error "
- "code path. This should be "
- "harmless.\n");
- }
- bmp->d.r.runlist[bmp->d.r.len].lcn = (ntfs_cluster_t)-1;
- bmp->d.r.runlist[bmp->d.r.len].len = (ntfs_cluster_t)0;
- break;
- default:
- BUG();
- }
- goto err_ret;
-}
-
-/* We need 0x48 bytes in total. */
-static int add_standard_information(ntfs_inode *ino)
-{
- ntfs_time64_t now;
- char data[0x30];
- char *position = data;
- ntfs_attribute *si;
-
- now = ntfs_now();
- NTFS_PUTU64(position + 0x00, now); /* File creation */
- NTFS_PUTU64(position + 0x08, now); /* Last modification */
- NTFS_PUTU64(position + 0x10, now); /* Last mod for MFT */
- NTFS_PUTU64(position + 0x18, now); /* Last access */
- NTFS_PUTU64(position + 0x20, 0); /* MSDOS file perms */
- NTFS_PUTU64(position + 0x28, 0); /* unknown */
- return ntfs_create_attr(ino, ino->vol->at_standard_information, 0,
- data, sizeof(data), &si);
-}
-
-static int add_filename(ntfs_inode *ino, ntfs_inode *dir,
- const unsigned char *filename, int length, ntfs_u32 flags)
-{
- unsigned char *position;
- unsigned int size;
- ntfs_time64_t now;
- int count, error;
- unsigned char* data;
- ntfs_attribute *fn;
-
- /* Work out the size. */
- size = 0x42 + 2 * length;
- data = ntfs_malloc(size);
- if (!data)
- return -ENOMEM;
- /* Search for a position. */
- position = data;
- NTFS_PUTINUM(position, dir); /* Inode num of dir */
- now = ntfs_now();
- NTFS_PUTU64(position + 0x08, now); /* File creation */
- NTFS_PUTU64(position + 0x10, now); /* Last modification */
- NTFS_PUTU64(position + 0x18, now); /* Last mod for MFT */
- NTFS_PUTU64(position + 0x20, now); /* Last access */
- /* FIXME: Get the following two sizes by finding the data attribute
- * in ino->attr and copying the corresponding fields from there.
- * If no data present then set to zero. In current implementation
- * add_data is called after add_filename so zero is correct on
- * creation. Need to change when we have hard links / support different
- * filename namespaces. (AIA) */
- NTFS_PUTS64(position + 0x28, 0); /* Allocated size */
- NTFS_PUTS64(position + 0x30, 0); /* Data size */
- NTFS_PUTU32(position + 0x38, flags); /* File flags */
- NTFS_PUTU32(position + 0x3c, 0); /* We don't use these
- * features yet. */
- NTFS_PUTU8(position + 0x40, length); /* Filename length */
- NTFS_PUTU8(position + 0x41, 0); /* Only long name */
- /* FIXME: This is madness. We are defining the POSIX namespace
- * for the filename here which can mean that the file will be
- * invisible when in Windows NT/2k! )-: (AIA) */
- position += 0x42;
- for (count = 0; count < length; count++) {
- NTFS_PUTU16(position + 2 * count, filename[count]);
- }
- error = ntfs_create_attr(ino, ino->vol->at_file_name, 0, data, size,
- &fn);
- if (!error)
- error = ntfs_dir_add(dir, ino, fn);
- ntfs_free(data);
- return error;
-}
-
-int add_security(ntfs_inode* ino, ntfs_inode* dir)
-{
- int error;
- char *buf;
- int size;
- ntfs_attribute* attr;
- ntfs_io io;
- ntfs_attribute *se;
-
- attr = ntfs_find_attr(dir, ino->vol->at_security_descriptor, 0);
- if (!attr)
- return -EOPNOTSUPP; /* Need security in directory. */
- size = attr->size;
- if (size > 512)
- return -EOPNOTSUPP;
- buf = ntfs_malloc(size);
- if (!buf)
- return -ENOMEM;
- io.fn_get = ntfs_get;
- io.fn_put = ntfs_put;
- io.param = buf;
- io.size = size;
- error = ntfs_read_attr(dir, ino->vol->at_security_descriptor, 0, 0,&io);
- if (!error && io.size != size)
- ntfs_error("wrong size in add_security\n");
- if (error) {
- ntfs_free(buf);
- return error;
- }
- /* FIXME: Consider ACL inheritance. */
- error = ntfs_create_attr(ino, ino->vol->at_security_descriptor,
- 0, buf, size, &se);
- ntfs_free(buf);
- return error;
-}
-
-static int add_data(ntfs_inode* ino, unsigned char *data, int length)
-{
- ntfs_attribute *da;
-
- return ntfs_create_attr(ino, ino->vol->at_data, 0, data, length, &da);
-}
-
-/*
- * We _could_ use 'dir' to help optimise inode allocation.
- *
- * FIXME: Need to undo what we do in ntfs_alloc_mft_record if we get an error
- * further on in ntfs_alloc_inode. Either fold the two functions to allow
- * proper undo or just deallocate the record from the mft bitmap. (AIA)
- */
-int ntfs_alloc_inode(ntfs_inode *dir, ntfs_inode *result, const char *filename,
- int namelen, ntfs_u32 flags)
-{
- ntfs_volume *vol = dir->vol;
- int err;
- ntfs_u8 buffer[2];
- ntfs_io io;
-
- err = ntfs_alloc_mft_record(vol, &(result->i_number));
- if (err) {
- if (err == -ENOSPC)
- ntfs_error(__FUNCTION__ "(): No free inodes.\n");
- return err;
- }
- /* Get the sequence number. */
- io.fn_put = ntfs_put;
- io.fn_get = ntfs_get;
- io.param = buffer;
- io.size = 2;
- err = ntfs_read_attr(vol->mft_ino, vol->at_data, 0,
- ((__s64)result->i_number << vol->mft_record_size_bits)
- + 0x10, &io);
- // FIXME: We are leaving the MFT in inconsistent state! (AIA)
- if (err)
- return err;
- /* Increment the sequence number skipping zero. */
- result->sequence_number = (NTFS_GETU16(buffer) + 1) & 0xffff;
- if (!result->sequence_number)
- result->sequence_number++;
- result->vol = vol;
- result->attr_count = 0;
- result->attrs = 0;
- result->record_count = 1;
- result->records = ntfs_calloc(8 * sizeof(int));
- if (!result->records)
- goto mem_err_out;
- result->records[0] = result->i_number;
- result->attr = ntfs_calloc(vol->mft_record_size);
- if (!result->attr) {
- ntfs_free(result->records);
- result->records = NULL;
- goto mem_err_out;
- }
- ntfs_fill_mft_header(result->attr, vol->mft_record_size,
- result->sequence_number, 1, 1);
- err = add_standard_information(result);
- if (!err)
- err = add_filename(result, dir, filename, namelen, flags);
- if (!err)
- err = add_security(result, dir);
- // FIXME: We are leaving the MFT in inconsistent state on error! (AIA)
- return err;
-mem_err_out:
- // FIXME: We are leaving the MFT in inconsistent state! (AIA)
- result->record_count = 0;
- result->attr = NULL;
- return -ENOMEM;
-}
-
-int ntfs_alloc_file(ntfs_inode *dir, ntfs_inode *result, char *filename,
- int namelen)
-{
- int err;
-
- err = ntfs_alloc_inode(dir, result, filename, namelen, 0);
- if (!err)
- err = add_data(result, 0, 0);
- return err;
-}
-
diff --git a/fs/ntfs/inode.h b/fs/ntfs/inode.h
deleted file mode 100644
index 96fcb824fbf5..000000000000
--- a/fs/ntfs/inode.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * inode.h - Header file for inode.c
- *
- * Copyright (C) 1997 Régis Duchesne
- * Copyright (C) 1998 Martin von Löwis
- * Copyright (c) 2001 Anton Altparmakov (AIA)
- */
-
-ntfs_attribute *ntfs_find_attr(ntfs_inode *ino, int type, char *name);
-
-int ntfs_read_attr(ntfs_inode *ino, int type, char *name, __s64 offset,
- ntfs_io *buf);
-
-int ntfs_write_attr(ntfs_inode *ino, int type, char *name, __s64 offset,
- ntfs_io *buf);
-
-int ntfs_init_inode(ntfs_inode *ino, ntfs_volume *vol, int inum);
-
-void ntfs_clear_inode(ntfs_inode *ino);
-
-int ntfs_check_mft_record(ntfs_volume *vol, char *record);
-
-int ntfs_alloc_inode(ntfs_inode *dir, ntfs_inode *result, const char *filename,
- int namelen, ntfs_u32);
-
-int ntfs_alloc_file(ntfs_inode *dir, ntfs_inode *result, char *filename,
- int namelen);
-
-int ntfs_update_inode(ntfs_inode *ino);
-
-int ntfs_vcn_to_lcn(ntfs_inode *ino, int vcn);
-
-int ntfs_readwrite_attr(ntfs_inode *ino, ntfs_attribute *attr, __s64 offset,
- ntfs_io *dest);
-
-int ntfs_allocate_attr_number(ntfs_inode *ino, int *result);
-
-int ntfs_decompress_run(unsigned char **data, int *length,
- ntfs_cluster_t *cluster, int *ctype);
-
-void ntfs_decompress(unsigned char *dest, unsigned char *src, ntfs_size_t l);
-
-int splice_runlists(ntfs_runlist **rl1, int *r1len, const ntfs_runlist *rl2,
- int r2len);
-
-/*
- * NOTE: Neither of the ntfs_*_bit functions are atomic! But we don't need
- * them atomic at present as we never operate on shared/cached bitmaps.
- */
-static __inline__ int ntfs_test_and_set_bit(unsigned char *byte, const int bit)
-{
- unsigned char *ptr = byte + (bit >> 3);
- int b = 1 << (bit & 7);
- int oldbit = *ptr & b ? 1 : 0;
- *ptr |= b;
- return oldbit;
-}
-
diff --git a/fs/ntfs/macros.h b/fs/ntfs/macros.h
deleted file mode 100644
index cb65cd12d924..000000000000
--- a/fs/ntfs/macros.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * macros.h
- *
- * Copyright (C) 1995 Martin von Löwis
- * Copyright (C) 1996 Régis Duchesne
- * Copyright (c) 2001 Anton Altaparmakov
- */
-#include <linux/ntfs_fs_i.h>
-#include <linux/fs.h>
-#include <asm/page.h>
-
-#define NTFS_FD(vol) ((vol)->u.fd)
-
-#define NTFS_SB(vol) ((struct super_block*)(vol)->sb)
-#define NTFS_SB2VOL(sb) (&(sb)->u.ntfs_sb)
-#define NTFS_INO2VOL(ino) (&((ino)->i_sb->u.ntfs_sb))
-static inline struct ntfs_i *ntfs_i(struct inode *inode)
-{
- return list_entry(inode, struct ntfs_i, vfs_inode);
-}
-#define NTFS_I(ino) (&ntfs_i(ino)->n)
-static inline struct inode *VFS_I(struct ntfs_inode_info *ntfs_ino)
-{
- return &list_entry(ntfs_ino, struct ntfs_i, n)->vfs_inode;
-}
-
-#define IS_MAGIC(a,b) (*(int*)(a) == *(int*)(b))
-#define IS_MFT_RECORD(a) IS_MAGIC((a),"FILE")
-#define IS_INDEX_RECORD(a) IS_MAGIC((a),"INDX")
-
-/* 'NTFS' in little endian */
-#define NTFS_SUPER_MAGIC 0x5346544E
-
-#define NTFS_AFLAG_RO 1
-#define NTFS_AFLAG_HIDDEN 2
-#define NTFS_AFLAG_SYSTEM 4
-#define NTFS_AFLAG_ARCHIVE 20
-#define NTFS_AFLAG_COMPRESSED 0x800
-#define NTFS_AFLAG_DIR 0x10000000
-
diff --git a/fs/ntfs/ntfsendian.h b/fs/ntfs/ntfsendian.h
deleted file mode 100644
index 1ec6946e8a18..000000000000
--- a/fs/ntfs/ntfsendian.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * ntfsendian.h
- *
- * Copyright (C) 1998, 1999 Martin von Löwis
- * Copyright (C) 1998 Joseph Malicki
- * Copyright (C) 1999 Werner Seiler
- * Copyright (C) 2001 Anton Altaparmakov (AIA)
- */
-#include <asm/byteorder.h>
-
-#define CPU_TO_LE16(a) __cpu_to_le16(a)
-#define CPU_TO_LE32(a) __cpu_to_le32(a)
-#define CPU_TO_LE64(a) __cpu_to_le64(a)
-
-#define LE16_TO_CPU(a) __cpu_to_le16(a)
-#define LE32_TO_CPU(a) __cpu_to_le32(a)
-#define LE64_TO_CPU(a) __cpu_to_le64(a)
-
-#define NTFS_GETU8(p) (*(ntfs_u8*)(p))
-#define NTFS_GETU16(p) ((ntfs_u16)LE16_TO_CPU(*(ntfs_u16*)(p)))
-#define NTFS_GETU24(p) ((ntfs_u32)NTFS_GETU16(p) | \
- ((ntfs_u32)NTFS_GETU8(((char*)(p)) + 2) << 16))
-#define NTFS_GETU32(p) ((ntfs_u32)LE32_TO_CPU(*(ntfs_u32*)(p)))
-#define NTFS_GETU40(p) ((ntfs_u64)NTFS_GETU32(p) | \
- (((ntfs_u64)NTFS_GETU8(((char*)(p)) + 4)) << 32))
-#define NTFS_GETU48(p) ((ntfs_u64)NTFS_GETU32(p) | \
- (((ntfs_u64)NTFS_GETU16(((char*)(p)) + 4)) << 32))
-#define NTFS_GETU56(p) ((ntfs_u64)NTFS_GETU32(p) | \
- (((ntfs_u64)NTFS_GETU24(((char*)(p)) + 4)) << 32))
-#define NTFS_GETU64(p) ((ntfs_u64)LE64_TO_CPU(*(ntfs_u64*)(p)))
-
- /* Macros writing unsigned integers */
-#define NTFS_PUTU8(p,v) ((*(ntfs_u8*)(p)) = (v))
-#define NTFS_PUTU16(p,v) ((*(ntfs_u16*)(p)) = CPU_TO_LE16(v))
-#define NTFS_PUTU24(p,v) NTFS_PUTU16(p, (v) & 0xFFFF);\
- NTFS_PUTU8(((char*)(p)) + 2, (v) >> 16)
-#define NTFS_PUTU32(p,v) ((*(ntfs_u32*)(p)) = CPU_TO_LE32(v))
-#define NTFS_PUTU64(p,v) ((*(ntfs_u64*)(p)) = CPU_TO_LE64(v))
-
- /* Macros reading signed integers */
-#define NTFS_GETS8(p) ((*(ntfs_s8*)(p)))
-#define NTFS_GETS16(p) ((ntfs_s16)LE16_TO_CPU(*(short*)(p)))
-#define NTFS_GETS24(p) (NTFS_GETU24(p) < 0x800000 ? \
- (int)NTFS_GETU24(p) : \
- (int)(NTFS_GETU24(p) - 0x1000000))
-#define NTFS_GETS32(p) ((ntfs_s32)LE32_TO_CPU(*(int*)(p)))
-#define NTFS_GETS40(p) (((ntfs_s64)NTFS_GETU32(p)) | \
- (((ntfs_s64)NTFS_GETS8(((char*)(p)) + 4)) << 32))
-#define NTFS_GETS48(p) (((ntfs_s64)NTFS_GETU32(p)) | \
- (((ntfs_s64)NTFS_GETS16(((char*)(p)) + 4)) << 32))
-#define NTFS_GETS56(p) (((ntfs_s64)NTFS_GETU32(p)) | \
- (((ntfs_s64)NTFS_GETS24(((char*)(p)) + 4)) << 32))
-#define NTFS_GETS64(p) ((ntfs_s64)NTFS_GETU64(p))
-
-#define NTFS_PUTS8(p,v) NTFS_PUTU8(p,v)
-#define NTFS_PUTS16(p,v) NTFS_PUTU16(p,v)
-#define NTFS_PUTS24(p,v) NTFS_PUTU24(p,v)
-#define NTFS_PUTS32(p,v) NTFS_PUTU32(p,v)
-#define NTFS_PUTS64(p,v) NTFS_PUTU64(p,v)
-
diff --git a/fs/ntfs/ntfstypes.h b/fs/ntfs/ntfstypes.h
deleted file mode 100644
index efd527d81e7a..000000000000
--- a/fs/ntfs/ntfstypes.h
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * ntfstypes.h - This file defines four things:
- * - Generic platform independent fixed-size types (e.g. ntfs_u32).
- * - Specific fixed-size types (e.g. ntfs_offset_t).
- * - Macros that read and write those types from and to byte arrays.
- * - Types derived from OS specific ones.
- *
- * Copyright (C) 1996, 1998, 1999 Martin von Löwis
- * Copyright (C) 2001 Anton Altaparmakov (AIA)
- */
-#include <linux/fs.h>
-#include "ntfsendian.h"
-#include <asm/types.h>
-
-/* Integral types */
-#ifndef NTFS_INTEGRAL_TYPES
-#define NTFS_INTEGRAL_TYPES
-typedef u8 ntfs_u8;
-typedef u16 ntfs_u16;
-typedef u32 ntfs_u32;
-typedef u64 ntfs_u64;
-typedef s8 ntfs_s8;
-typedef s16 ntfs_s16;
-typedef s32 ntfs_s32;
-typedef s64 ntfs_s64;
-#endif
-
-/* Unicode character type */
-#ifndef NTFS_WCHAR_T
-#define NTFS_WCHAR_T
-typedef u16 ntfs_wchar_t;
-#endif
-/* File offset */
-#ifndef NTFS_OFFSET_T
-#define NTFS_OFFSET_T
-typedef s64 ntfs_offset_t;
-#endif
-/* UTC */
-#ifndef NTFS_TIME64_T
-#define NTFS_TIME64_T
-typedef u64 ntfs_time64_t;
-#endif
-/*
- * This is really signed long long. So we support only volumes up to 2Tb. This
- * is ok as Win2k also only uses 32-bits to store clusters.
- * Whatever you do keep this a SIGNED value or a lot of NTFS users with
- * corrupted filesystems will lynch you! It causes massive fs corruption when
- * unsigned due to the nature of many checks relying on being performed on
- * signed quantities. (AIA)
- */
-#ifndef NTFS_CLUSTER_T
-#define NTFS_CLUSTER_T
-typedef s32 ntfs_cluster_t;
-#endif
-
-/* Architecture independent macros. */
-
-/* PUTU32 would not clear all bytes. */
-#define NTFS_PUTINUM(p,i) NTFS_PUTU64(p, i->i_number); \
- NTFS_PUTU16(((char*)p) + 6, i->sequence_number)
-
-/* System dependent types. */
-#include <asm/posix_types.h>
-#ifndef NTMODE_T
-#define NTMODE_T
-typedef __kernel_mode_t ntmode_t;
-#endif
-#ifndef NTFS_UID_T
-#define NTFS_UID_T
-typedef uid_t ntfs_uid_t;
-#endif
-#ifndef NTFS_GID_T
-#define NTFS_GID_T
-typedef gid_t ntfs_gid_t;
-#endif
-#ifndef NTFS_SIZE_T
-#define NTFS_SIZE_T
-typedef __kernel_size_t ntfs_size_t;
-#endif
-#ifndef NTFS_TIME_T
-#define NTFS_TIME_T
-typedef __kernel_time_t ntfs_time_t;
-#endif
-
diff --git a/fs/ntfs/struct.h b/fs/ntfs/struct.h
deleted file mode 100644
index 0cb909b037e4..000000000000
--- a/fs/ntfs/struct.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * struct.h - Structure definitions
- *
- * Copyright (C) 1997 Régis Duchesne
- * Copyright (C) 2000-2001 Anton Altaparmakov (AIA)
- */
-#include <linux/ntfs_fs.h>
-
-/* Necessary forward definition. */
-struct ntfs_inode;
-
-/* Which files should be returned from a director listing. */
-#define ngt_dos 1 /* only short names, no system files */
-#define ngt_nt 2 /* only long names, all-uppercase becomes
- * all-lowercase, no system files */
-#define ngt_posix 3 /* all names except system files */
-#define ngt_full 4 /* all entries */
-
-typedef struct ntfs_sb_info ntfs_volume;
-
-typedef struct {
- ntfs_cluster_t lcn;
- ntfs_cluster_t len;
-} ntfs_runlist;
-
-typedef struct ntfs_attribute {
- int type;
- ntfs_u16 *name;
- int namelen;
- int attrno;
- __s64 size, allocated, initialized, compsize;
- ATTR_FLAGS flags;
- __u8 resident, indexed;
- int cengine;
- union {
- void *data; /* if resident */
- struct {
- ntfs_runlist *runlist;
- unsigned long len;
- } r;
- } d;
-} ntfs_attribute;
-
-typedef struct ntfs_inode_info ntfs_inode;
-
-/* Structure to define IO to user buffer. do_read means that the destination
- * has to be written using fn_put, do_write means that the destination has to
- * read using fn_get. So, do_read is from a user's point of view, while put and
- * get are from the driver's point of view. The first argument is always the
- * destination of the IO. */
-typedef struct ntfs_io{
- int do_read;
- void (*fn_put)(struct ntfs_io *dest, void *buf, ntfs_size_t);
- void (*fn_get)(void *buf, struct ntfs_io *src, ntfs_size_t len);
- void *param;
- unsigned long size;
-} ntfs_io;
-
-#if 0
-typedef struct {
- ntfs_volume *vol;
- ntfs_inode *ino;
- int type;
- char *name;
- int mftno;
- int start_vcn;
-} ntfs_attrlist_item;
-#endif
-
diff --git a/fs/ntfs/super.c b/fs/ntfs/super.c
deleted file mode 100644
index 296f0f1fa29f..000000000000
--- a/fs/ntfs/super.c
+++ /dev/null
@@ -1,1413 +0,0 @@
-/*
- * super.c
- *
- * Copyright (C) 1995-1997, 1999 Martin von Löwis
- * Copyright (C) 1996-1997 Régis Duchesne
- * Copyright (C) 1999 Steve Dodd
- * Copyright (C) 2000-2001 Anton Altparmakov (AIA)
- */
-
-#include <linux/ntfs_fs.h>
-#include <linux/errno.h>
-#include <linux/bitops.h>
-#include <linux/module.h>
-#include "ntfstypes.h"
-#include "struct.h"
-#include "super.h"
-#include "macros.h"
-#include "inode.h"
-#include "support.h"
-#include "util.h"
-#include <linux/smp_lock.h>
-
-/* All important structures in NTFS use 2 consistency checks:
- * . a magic structure identifier (FILE, INDX, RSTR, RCRD...)
- * . a fixup technique : the last word of each sector (called a fixup) of a
- * structure's record should end with the word at offset <n> of the first
- * sector, and if it is the case, must be replaced with the words following
- * <n>. The value of <n> and the number of fixups is taken from the fields
- * at the offsets 4 and 6. Note that the sector size is defined as
- * NTFS_SECTOR_SIZE and not as the hardware sector size (this is concordant
- * with what the Windows NTFS driver does).
- *
- * This function performs these 2 checks, and _fails_ if:
- * . the input size is invalid
- * . the fixup header is invalid
- * . the size does not match the number of sectors
- * . the magic identifier is wrong
- * . a fixup is invalid
- */
-int ntfs_fixup_record(char *record, char *magic, int size)
-{
- int start, count, offset;
- ntfs_u16 fixup;
-
- if (!IS_MAGIC(record, magic))
- return 0;
- start = NTFS_GETU16(record + 4);
- count = NTFS_GETU16(record + 6) - 1;
- if (size & (NTFS_SECTOR_SIZE - 1) || start & 1 ||
- start + count * 2 > size || size >> 9 != count) {
- if (size <= 0)
- printk(KERN_ERR "NTFS: BUG: ntfs_fixup_record() got "
- "zero size! Please report this to "
- "linux-ntfs-dev@lists.sf.net\n");
- return 0;
- }
- fixup = NTFS_GETU16(record + start);
- start += 2;
- offset = NTFS_SECTOR_SIZE - 2;
- while (count--) {
- if (NTFS_GETU16(record + offset) != fixup)
- return 0;
- NTFS_PUTU16(record + offset, NTFS_GETU16(record + start));
- start += 2;
- offset += NTFS_SECTOR_SIZE;
- }
- return 1;
-}
-
-/*
- * Get vital informations about the ntfs partition from the boot sector.
- * Return 0 on success or -1 on error.
- */
-int ntfs_init_volume(ntfs_volume *vol, char *boot)
-{
- int sectors_per_cluster_bits;
- __s64 ll;
- ntfs_cluster_t mft_zone_size, tc;
-
- /* System defined default values, in case we don't load $AttrDef. */
- vol->at_standard_information = 0x10;
- vol->at_attribute_list = 0x20;
- vol->at_file_name = 0x30;
- vol->at_volume_version = 0x40;
- vol->at_security_descriptor = 0x50;
- vol->at_volume_name = 0x60;
- vol->at_volume_information = 0x70;
- vol->at_data = 0x80;
- vol->at_index_root = 0x90;
- vol->at_index_allocation = 0xA0;
- vol->at_bitmap = 0xB0;
- vol->at_symlink = 0xC0;
- /* Sector size. */
- vol->sector_size = NTFS_GETU16(boot + 0xB);
- ntfs_debug(DEBUG_FILE3, "ntfs_init_volume: vol->sector_size = 0x%x\n",
- vol->sector_size);
- ntfs_debug(DEBUG_FILE3, "ntfs_init_volume: sectors_per_cluster = "
- "0x%x\n", NTFS_GETU8(boot + 0xD));
- sectors_per_cluster_bits = ffs(NTFS_GETU8(boot + 0xD)) - 1;
- ntfs_debug(DEBUG_FILE3, "ntfs_init_volume: sectors_per_cluster_bits "
- "= 0x%x\n", sectors_per_cluster_bits);
- vol->mft_clusters_per_record = NTFS_GETS8(boot + 0x40);
- ntfs_debug(DEBUG_FILE3, "ntfs_init_volume: vol->mft_clusters_per_record"
- " = 0x%x\n", vol->mft_clusters_per_record);
- vol->index_clusters_per_record = NTFS_GETS8(boot + 0x44);
- ntfs_debug(DEBUG_FILE3, "ntfs_init_volume: "
- "vol->index_clusters_per_record = 0x%x\n",
- vol->index_clusters_per_record);
- vol->cluster_size = vol->sector_size << sectors_per_cluster_bits;
- vol->cluster_size_bits = ffs(vol->cluster_size) - 1;
- ntfs_debug(DEBUG_FILE3, "ntfs_init_volume: vol->cluster_size = 0x%x\n",
- vol->cluster_size);
- ntfs_debug(DEBUG_FILE3, "ntfs_init_volume: vol->cluster_size_bits = "
- "0x%x\n", vol->cluster_size_bits);
- if (vol->mft_clusters_per_record > 0)
- vol->mft_record_size = vol->cluster_size <<
- (ffs(vol->mft_clusters_per_record) - 1);
- else
- /*
- * When mft_record_size < cluster_size, mft_clusters_per_record
- * = -log2(mft_record_size) bytes. mft_record_size normaly is
- * 1024 bytes, which is encoded as 0xF6 (-10 in decimal).
- */
- vol->mft_record_size = 1 << -vol->mft_clusters_per_record;
- vol->mft_record_size_bits = ffs(vol->mft_record_size) - 1;
- ntfs_debug(DEBUG_FILE3, "ntfs_init_volume: vol->mft_record_size = 0x%x"
- "\n", vol->mft_record_size);
- ntfs_debug(DEBUG_FILE3, "ntfs_init_volume: vol->mft_record_size_bits = "
- "0x%x\n", vol->mft_record_size_bits);
- if (vol->index_clusters_per_record > 0)
- vol->index_record_size = vol->cluster_size <<
- (ffs(vol->index_clusters_per_record) - 1);
- else
- /*
- * When index_record_size < cluster_size,
- * index_clusters_per_record = -log2(index_record_size) bytes.
- * index_record_size normaly equals 4096 bytes, which is
- * encoded as 0xF4 (-12 in decimal).
- */
- vol->index_record_size = 1 << -vol->index_clusters_per_record;
- vol->index_record_size_bits = ffs(vol->index_record_size) - 1;
- ntfs_debug(DEBUG_FILE3, "ntfs_init_volume: vol->index_record_size = "
- "0x%x\n", vol->index_record_size);
- ntfs_debug(DEBUG_FILE3, "ntfs_init_volume: vol->index_record_size_bits "
- "= 0x%x\n", vol->index_record_size_bits);
- /*
- * Get the size of the volume in clusters (ofs 0x28 is nr_sectors) and
- * check for 64-bit-ness. Windows currently only uses 32 bits to save
- * the clusters so we do the same as it is much faster on 32-bit CPUs.
- */
- ll = NTFS_GETS64(boot + 0x28) >> sectors_per_cluster_bits;
- if (ll >= (__s64)1 << 31) {
- ntfs_error("Cannot handle 64-bit clusters. Please inform "
- "linux-ntfs-dev@lists.sf.net that you got this "
- "error.\n");
- return -1;
- }
- vol->nr_clusters = (ntfs_cluster_t)ll;
- ntfs_debug(DEBUG_FILE3, "ntfs_init_volume: vol->nr_clusters = 0x%x\n",
- vol->nr_clusters);
- vol->mft_lcn = (ntfs_cluster_t)NTFS_GETS64(boot + 0x30);
- vol->mft_mirr_lcn = (ntfs_cluster_t)NTFS_GETS64(boot + 0x38);
- /* Determine MFT zone size. */
- mft_zone_size = vol->nr_clusters;
- switch (vol->mft_zone_multiplier) { /* % of volume size in clusters */
- case 4:
- mft_zone_size >>= 1; /* 50% */
- break;
- case 3:
- mft_zone_size = mft_zone_size * 3 >> 3; /* 37.5% */
- break;
- case 2:
- mft_zone_size >>= 2; /* 25% */
- break;
- /* case 1: */
- default:
- mft_zone_size >>= 3; /* 12.5% */
- break;
- }
- /* Setup mft zone. */
- vol->mft_zone_start = vol->mft_zone_pos = vol->mft_lcn;
- ntfs_debug(DEBUG_FILE3, "ntfs_init_volume: vol->mft_zone_pos = %x\n",
- vol->mft_zone_pos);
- /*
- * Calculate the mft_lcn for an unmodified NTFS volume (see mkntfs
- * source) and if the actual mft_lcn is in the expected place or even
- * further to the front of the volume, extend the mft_zone to cover the
- * beginning of the volume as well. This is in order to protect the
- * area reserved for the mft bitmap as well within the mft_zone itself.
- * On non-standard volumes we don't protect it as well as the overhead
- * would be higher than the speed increase we would get by doing it.
- */
- tc = (8192 + 2 * vol->cluster_size - 1) / vol->cluster_size;
- if (tc * vol->cluster_size < 16 * 1024)
- tc = (16 * 1024 + vol->cluster_size - 1) / vol->cluster_size;
- if (vol->mft_zone_start <= tc)
- vol->mft_zone_start = (ntfs_cluster_t)0;
- ntfs_debug(DEBUG_FILE3, "ntfs_init_volume: vol->mft_zone_start = %x\n",
- vol->mft_zone_start);
- /*
- * Need to cap the mft zone on non-standard volumes so that it does
- * not point outside the boundaries of the volume, we do this by
- * halving the zone size until we are inside the volume.
- */
- vol->mft_zone_end = vol->mft_lcn + mft_zone_size;
- while (vol->mft_zone_end >= vol->nr_clusters) {
- mft_zone_size >>= 1;
- vol->mft_zone_end = vol->mft_lcn + mft_zone_size;
- }
- ntfs_debug(DEBUG_FILE3, "ntfs_init_volume: vol->mft_zone_end = %x\n",
- vol->mft_zone_end);
- /*
- * Set the current position within each data zone to the start of the
- * respective zone.
- */
- vol->data1_zone_pos = vol->mft_zone_end;
- ntfs_debug(DEBUG_FILE3, "ntfs_init_volume: vol->data1_zone_pos = %x\n",
- vol->data1_zone_pos);
- vol->data2_zone_pos = (ntfs_cluster_t)0;
- ntfs_debug(DEBUG_FILE3, "ntfs_init_volume: vol->data2_zone_pos = %x\n",
- vol->data2_zone_pos);
- /* Set the mft data allocation position to mft record 24. */
- vol->mft_data_pos = 24UL;
- /* This will be initialized later. */
- vol->upcase = 0;
- vol->upcase_length = 0;
- vol->mft_ino = 0;
- return 0;
-}
-
-static void ntfs_init_upcase(ntfs_inode *upcase)
-{
- ntfs_io io;
-#define UPCASE_LENGTH 256
- upcase->vol->upcase = ntfs_malloc(UPCASE_LENGTH << 1);
- if (!upcase->vol->upcase)
- return;
- io.fn_put = ntfs_put;
- io.fn_get = 0;
- io.param = (char*)upcase->vol->upcase;
- io.size = UPCASE_LENGTH << 1;
- ntfs_read_attr(upcase, upcase->vol->at_data, 0, 0, &io);
- upcase->vol->upcase_length = io.size >> 1;
-}
-
-static int process_attrdef(ntfs_inode* attrdef, ntfs_u8* def)
-{
- int type = NTFS_GETU32(def+0x80);
- int check_type = 0;
- ntfs_volume *vol = attrdef->vol;
- ntfs_u16* name = (ntfs_u16*)def;
-
- if (!type) {
- ntfs_debug(DEBUG_OTHER, "process_atrdef: finished processing "
- "and returning 1\n");
- return 1;
- }
- if (ntfs_ua_strncmp(name, "$STANDARD_INFORMATION", 64) == 0) {
- vol->at_standard_information = type;
- check_type = 0x10;
- } else if (ntfs_ua_strncmp(name, "$ATTRIBUTE_LIST", 64) == 0) {
- vol->at_attribute_list = type;
- check_type = 0x20;
- } else if (ntfs_ua_strncmp(name, "$FILE_NAME", 64) == 0) {
- vol->at_file_name = type;
- check_type = 0x30;
- } else if (ntfs_ua_strncmp(name, "$VOLUME_VERSION", 64) == 0) {
- vol->at_volume_version = type;
- check_type = 0x40;
- } else if (ntfs_ua_strncmp(name, "$SECURITY_DESCRIPTOR", 64) == 0) {
- vol->at_security_descriptor = type;
- check_type = 0x50;
- } else if (ntfs_ua_strncmp(name, "$VOLUME_NAME", 64) == 0) {
- vol->at_volume_name = type;
- check_type = 0x60;
- } else if (ntfs_ua_strncmp(name, "$VOLUME_INFORMATION", 64) == 0) {
- vol->at_volume_information = type;
- check_type = 0x70;
- } else if (ntfs_ua_strncmp(name, "$DATA", 64) == 0) {
- vol->at_data = type;
- check_type = 0x80;
- } else if (ntfs_ua_strncmp(name, "$INDEX_ROOT", 64) == 0) {
- vol->at_index_root = type;
- check_type = 0x90;
- } else if (ntfs_ua_strncmp(name, "$INDEX_ALLOCATION", 64) == 0) {
- vol->at_index_allocation = type;
- check_type = 0xA0;
- } else if (ntfs_ua_strncmp(name, "$BITMAP", 64) == 0) {
- vol->at_bitmap = type;
- check_type = 0xB0;
- } else if (ntfs_ua_strncmp(name, "$SYMBOLIC_LINK", 64) == 0 ||
- ntfs_ua_strncmp(name, "$REPARSE_POINT", 64) == 0) {
- vol->at_symlink = type;
- check_type = 0xC0;
- }
- if (check_type && check_type != type) {
- ntfs_error("process_attrdef: unexpected type 0x%x for 0x%x\n",
- type, check_type);
- return -EINVAL;
- }
- ntfs_debug(DEBUG_OTHER, "process_attrdef: found %s attribute of type "
- "0x%x\n", check_type ? "known" : "unknown", type);
- return 0;
-}
-
-int ntfs_init_attrdef(ntfs_inode* attrdef)
-{
- ntfs_u8 *buf;
- ntfs_io io;
- __s64 offset;
- unsigned i;
- int error;
- ntfs_attribute *data;
-
- ntfs_debug(DEBUG_BSD, "Entered ntfs_init_attrdef()\n");
- buf = ntfs_malloc(4050); /* 90*45 */
- if (!buf)
- return -ENOMEM;
- io.fn_put = ntfs_put;
- io.fn_get = ntfs_get;
- io.do_read = 1;
- offset = 0;
- data = ntfs_find_attr(attrdef, attrdef->vol->at_data, 0);
- ntfs_debug(DEBUG_BSD, "In ntfs_init_attrdef() after call to "
- "ntfs_find_attr.\n");
- if (!data) {
- ntfs_free(buf);
- return -EINVAL;
- }
- do {
- io.param = buf;
- io.size = 4050;
- ntfs_debug(DEBUG_BSD, "In ntfs_init_attrdef() going to call "
- "ntfs_readwrite_attr.\n");
- error = ntfs_readwrite_attr(attrdef, data, offset, &io);
- ntfs_debug(DEBUG_BSD, "In ntfs_init_attrdef() after call to "
- "ntfs_readwrite_attr.\n");
- for (i = 0; !error && i <= io.size - 0xA0; i += 0xA0) {
- ntfs_debug(DEBUG_BSD, "In ntfs_init_attrdef() going "
- "to call process_attrdef.\n");
- error = process_attrdef(attrdef, buf + i);
- ntfs_debug(DEBUG_BSD, "In ntfs_init_attrdef() after "
- "call to process_attrdef.\n");
- }
- offset += 4096;
- } while (!error && io.size);
- ntfs_debug(DEBUG_BSD, "Exiting ntfs_init_attrdef()\n");
- ntfs_free(buf);
- return error == 1 ? 0 : error;
-}
-
-/* ntfs_get_version will determine the NTFS version of the volume and will
- * return the version in a BCD format, with the MSB being the major version
- * number and the LSB the minor one. Otherwise return <0 on error.
- * Example: version 3.1 will be returned as 0x0301. This has the obvious
- * limitation of not coping with version numbers above 0x80 but that shouldn't
- * be a problem... */
-int ntfs_get_version(ntfs_inode* volume)
-{
- ntfs_attribute *volinfo;
-
- volinfo = ntfs_find_attr(volume, volume->vol->at_volume_information, 0);
- if (!volinfo)
- return -EINVAL;
- if (!volinfo->resident) {
- ntfs_error("Volume information attribute is not resident!\n");
- return -EINVAL;
- }
- return ((ntfs_u8*)volinfo->d.data)[8] << 8 |
- ((ntfs_u8*)volinfo->d.data)[9];
-}
-
-int ntfs_load_special_files(ntfs_volume *vol)
-{
- int error;
- ntfs_inode upcase, attrdef, volume;
-
- vol->mft_ino = (ntfs_inode*)ntfs_calloc(sizeof(ntfs_inode));
- vol->mftmirr = (ntfs_inode*)ntfs_calloc(sizeof(ntfs_inode));
- vol->bitmap = (ntfs_inode*)ntfs_calloc(sizeof(ntfs_inode));
- vol->ino_flags = 4 | 2 | 1;
- error = -ENOMEM;
- ntfs_debug(DEBUG_BSD, "Going to load MFT\n");
- if (!vol->mft_ino || (error = ntfs_init_inode(vol->mft_ino, vol,
- FILE_Mft))) {
- ntfs_error("Problem loading MFT\n");
- return error;
- }
- ntfs_debug(DEBUG_BSD, "Going to load MIRR\n");
- if ((error = ntfs_init_inode(vol->mftmirr, vol, FILE_MftMirr))) {
- ntfs_error("Problem %d loading MFTMirr\n", error);
- return error;
- }
- ntfs_debug(DEBUG_BSD, "Going to load BITMAP\n");
- if ((error = ntfs_init_inode(vol->bitmap, vol, FILE_BitMap))) {
- ntfs_error("Problem loading Bitmap\n");
- return error;
- }
- ntfs_debug(DEBUG_BSD, "Going to load UPCASE\n");
- error = ntfs_init_inode(&upcase, vol, FILE_UpCase);
- if (error)
- return error;
- ntfs_init_upcase(&upcase);
- ntfs_clear_inode(&upcase);
- ntfs_debug(DEBUG_BSD, "Going to load ATTRDEF\n");
- error = ntfs_init_inode(&attrdef, vol, FILE_AttrDef);
- if (error)
- return error;
- error = ntfs_init_attrdef(&attrdef);
- ntfs_clear_inode(&attrdef);
- if (error)
- return error;
-
- /* Check for NTFS version and if Win2k version (ie. 3.0+) do not allow
- * write access since the driver write support is broken. */
- ntfs_debug(DEBUG_BSD, "Going to load VOLUME\n");
- error = ntfs_init_inode(&volume, vol, FILE_Volume);
- if (error)
- return error;
- if ((error = ntfs_get_version(&volume)) >= 0x0300 &&
- !(NTFS_SB(vol)->s_flags & MS_RDONLY)) {
- NTFS_SB(vol)->s_flags |= MS_RDONLY;
- ntfs_error("Warning! NTFS volume version is Win2k+: Mounting "
- "read-only\n");
- }
- ntfs_clear_inode(&volume);
- if (error < 0)
- return error;
- ntfs_debug(DEBUG_BSD, "NTFS volume is v%d.%d\n", error >> 8,
- error & 0xff);
- return 0;
-}
-
-int ntfs_release_volume(ntfs_volume *vol)
-{
- if (((vol->ino_flags & 1) == 1) && vol->mft_ino) {
- ntfs_clear_inode(vol->mft_ino);
- ntfs_free(vol->mft_ino);
- vol->mft_ino = 0;
- }
- if (((vol->ino_flags & 2) == 2) && vol->mftmirr) {
- ntfs_clear_inode(vol->mftmirr);
- ntfs_free(vol->mftmirr);
- vol->mftmirr = 0;
- }
- if (((vol->ino_flags & 4) == 4) && vol->bitmap) {
- ntfs_clear_inode(vol->bitmap);
- ntfs_free(vol->bitmap);
- vol->bitmap = 0;
- }
- ntfs_free(vol->mft);
- ntfs_free(vol->upcase);
- return 0;
-}
-
-/*
- * Writes the volume size (units of clusters) into vol_size.
- * Returns 0 if successful or error.
- */
-int ntfs_get_volumesize(ntfs_volume *vol, ntfs_s64 *vol_size)
-{
- ntfs_io io;
- char *cluster0;
-
- if (!vol_size)
- return -EFAULT;
- cluster0 = ntfs_malloc(vol->cluster_size);
- if (!cluster0)
- return -ENOMEM;
- io.fn_put = ntfs_put;
- io.fn_get = ntfs_get;
- io.param = cluster0;
- io.do_read = 1;
- io.size = vol->cluster_size;
- ntfs_getput_clusters(vol, 0, 0, &io);
- *vol_size = NTFS_GETU64(cluster0 + 0x28) >>
- (ffs(NTFS_GETU8(cluster0 + 0xD)) - 1);
- ntfs_free(cluster0);
- return 0;
-}
-
-static int nc[16]={4,3,3,2,3,2,2,1,3,2,2,1,2,1,1,0};
-
-int ntfs_get_free_cluster_count(ntfs_inode *bitmap)
-{
- ntfs_io io;
- int offset, error, clusters;
- unsigned char *bits = ntfs_malloc(2048);
- if (!bits)
- return -ENOMEM;
- offset = clusters = 0;
- io.fn_put = ntfs_put;
- io.fn_get = ntfs_get;
- while (1) {
- register int i;
- io.param = bits;
- io.size = 2048;
- error = ntfs_read_attr(bitmap, bitmap->vol->at_data, 0, offset,
- &io);
- if (error || io.size == 0)
- break;
- /* I never thought I would do loop unrolling some day */
- for (i = 0; i < io.size - 8; ) {
- clusters+=nc[bits[i]>>4];clusters+=nc[bits[i++] & 0xF];
- clusters+=nc[bits[i]>>4];clusters+=nc[bits[i++] & 0xF];
- clusters+=nc[bits[i]>>4];clusters+=nc[bits[i++] & 0xF];
- clusters+=nc[bits[i]>>4];clusters+=nc[bits[i++] & 0xF];
- clusters+=nc[bits[i]>>4];clusters+=nc[bits[i++] & 0xF];
- clusters+=nc[bits[i]>>4];clusters+=nc[bits[i++] & 0xF];
- clusters+=nc[bits[i]>>4];clusters+=nc[bits[i++] & 0xF];
- clusters+=nc[bits[i]>>4];clusters+=nc[bits[i++] & 0xF];
- }
- while (i < io.size) {
- clusters += nc[bits[i] >> 4];
- clusters += nc[bits[i++] & 0xF];
- }
- offset += io.size;
- }
- ntfs_free(bits);
- return clusters;
-}
-
-/*
- * Insert the fixups for the record. The number and location of the fixes
- * is obtained from the record header but we double check with @rec_size and
- * use that as the upper boundary, if necessary overwriting the count value in
- * the record header.
- *
- * We return 0 on success or -1 if fixup header indicated the beginning of the
- * update sequence array to be beyond the valid limit.
- */
-int ntfs_insert_fixups(unsigned char *rec, int rec_size)
-{
- int first;
- int count;
- int offset = -2;
- ntfs_u16 fix;
-
- first = NTFS_GETU16(rec + 4);
- count = (rec_size >> NTFS_SECTOR_BITS) + 1;
- if (first + count * 2 > NTFS_SECTOR_SIZE - 2) {
- printk(KERN_CRIT "NTFS: ntfs_insert_fixups() detected corrupt "
- "NTFS record update sequence array position. - "
- "Cannot hotfix.\n");
- return -1;
- }
- if (count != NTFS_GETU16(rec + 6)) {
- printk(KERN_ERR "NTFS: ntfs_insert_fixups() detected corrupt "
- "NTFS record update sequence array size. - "
- "Applying hotfix.\n");
- NTFS_PUTU16(rec + 6, count);
- }
- fix = (NTFS_GETU16(rec + first) + 1) & 0xffff;
- if (fix == 0xffff || !fix)
- fix = 1;
- NTFS_PUTU16(rec + first, fix);
- count--;
- while (count--) {
- first += 2;
- offset += NTFS_SECTOR_SIZE;
- NTFS_PUTU16(rec + first, NTFS_GETU16(rec + offset));
- NTFS_PUTU16(rec + offset, fix);
- }
- return 0;
-}
-
-/**
- * ntfs_allocate_clusters - allocate logical clusters on an ntfs volume
- * @vol: volume on which to allocate clusters
- * @location: preferred location for first allocated cluster
- * @count: number of clusters to allocate
- * @rl: address of pointer in which to return the allocated run list
- * @rl_len: the number of elements returned in @*rl
- *
- * Allocate @*count clusters (LCNs), preferably beginning at @*location in the
- * bitmap of the volume @vol. If @*location is -1, it does not matter where the
- * clusters are. @rl is the address of a ntfs_runlist pointer which this
- * function will allocate and fill with the runlist of the allocated clusters.
- * It is the callers responsibility to ntfs_vfree() @*rl after she is finished
- * with it. If the function was not successful, @*rl will be set to NULL.
- * @*rl_len will contain the number of ntfs_runlist elements in @*rl or 0 if
- * @*rl is NULL.
- *
- * Return 0 on success, or -errno on error. On success, @*location and @*count
- * say what was really allocated. On -ENOSPC, @*location and @*count say what
- * could have been allocated. If nothing could be allocated or a different
- * error occured, @*location = -1 and @*count = 0.
- *
- * There are two data zones. First is the area between the end of the mft zone
- * and the end of the volume, and second is the area between the start of the
- * volume and the start of the mft zone. On unmodified/standard volumes, the
- * second mft zone doesn't exist due to the mft zone being expanded to cover
- * the start of volume in order to reserve space for the mft bitmap attribute.
- *
- * This is not the prettiest function but the complexity stems from the need of
- * implementing the mft vs data zoned approach and from the fact that we have
- * access to the lcn bitmap in portions of PAGE_SIZE bytes at a time, so we
- * need to cope with crossing over boundaries of two pages. Further, the fact
- * that the allocator allows for caller supplied hints as to the location of
- * where allocation should begin and the fact that the allocator keeps track of
- * where in the data zones the next natural allocation should occur, contribute
- * to the complexity of the function. But it should all be worthwhile, because
- * this allocator should: 1) be a full implementation of the MFT zone approach
- * used by Windows, 2) cause reduction in fragmentation as much as possible,
- * and 3) be speedy in allocations (the code is not optimized for speed, but
- * the algorithm is, so further speed improvements are probably possible).
- *
- * FIXME: Really need finer-grained locking but this will do for the moment. I
- * just want to kill all races and have a working allocator. When that is done,
- * we can beautify... (AIA)
- *
- * FIXME: We should be monitoring cluster allocation and increment the MFT zone
- * size dynamically but this is something for the future. We will just cause
- * heavier fragmentation by not doing it and I am not even sure Windows would
- * grow the MFT zone dynamically, so might even be correct not doing this. The
- * overhead in doing dynamic MFT zone expansion would be very large and unlikely
- * worth the effort. (AIA)
- *
- * TODO: I have added in double the required zone position pointer wrap around
- * logic which can be optimized to having only one of the two logic sets.
- * However, having the double logic will work fine, but if we have only one of
- * the sets and we get it wrong somewhere, then we get into trouble, so
- * removing the duplicate logic requires _very_ careful consideration of _all_
- * possible code paths. So at least for now, I am leaving the double logic -
- * better safe than sorry... (AIA)
- */
-int ntfs_allocate_clusters(ntfs_volume *vol, ntfs_cluster_t *location,
- ntfs_cluster_t *count, ntfs_runlist **rl, int *rl_len,
- const NTFS_CLUSTER_ALLOCATION_ZONES zone)
-{
- ntfs_runlist *rl2 = NULL, *rlt;
- ntfs_attribute *data;
- ntfs_cluster_t buf_pos, zone_start, zone_end, mft_zone_size;
- ntfs_cluster_t lcn, last_read_pos, prev_lcn = (ntfs_cluster_t)0;
- ntfs_cluster_t initial_location, prev_run_len = (ntfs_cluster_t)0;
- ntfs_cluster_t clusters = (ntfs_cluster_t)0;
- unsigned char *buf, *byte, bit, search_zone, done_zones;
- unsigned char pass, need_writeback;
- int rlpos = 0, rlsize, buf_size, err = 0;
- ntfs_io io;
-
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Entering with *location = "
- "0x%x, *count = 0x%x, zone = %s_ZONE.\n", *location,
- *count, zone == DATA_ZONE ? "DATA" : "MFT");
- buf = (char*)__get_free_page(GFP_NOFS);
- if (!buf) {
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Returning "
- "-ENOMEM.\n");
- return -ENOMEM;
- }
- io.fn_put = ntfs_put;
- io.fn_get = ntfs_get;
- lock_kernel();
- /* Get the $DATA attribute of $Bitmap. */
- data = ntfs_find_attr(vol->bitmap, vol->at_data, 0);
- if (!data) {
- err = -EINVAL;
- goto err_ret;
- }
- /*
- * If no specific location was requested, use the current data zone
- * position, otherwise use the requested location but make sure it lies
- * outside the mft zone. Also set done_zones to 0 (no zones done) and
- * pass depending on whether we are starting inside a zone (1) or
- * at the beginning of a zone (2). If requesting from the MFT_ZONE, then
- * we either start at the current position within the mft zone or at the
- * specified position and if the latter is out of bounds then we start
- * at the beginning of the MFT_ZONE.
- */
- done_zones = 0;
- pass = 1;
- /*
- * zone_start and zone_end are the current search range. search_zone
- * is 1 for mft zone, 2 for data zone 1 (end of mft zone till end of
- * volume) and 4 for data zone 2 (start of volume till start of mft
- * zone).
- */
- zone_start = *location;
- if (zone_start < 0) {
- if (zone == DATA_ZONE)
- zone_start = vol->data1_zone_pos;
- else
- zone_start = vol->mft_zone_pos;
- if (!zone_start)
- /*
- * Zone starts at beginning of volume which means a
- * single pass is sufficient.
- */
- pass = 2;
- } else if (zone_start >= vol->mft_zone_start && zone_start <
- vol->mft_zone_end && zone == DATA_ZONE) {
- zone_start = vol->mft_zone_end;
- pass = 2;
- } else if ((zone_start < vol->mft_zone_start || zone_start >=
- vol->mft_zone_end) && zone == MFT_ZONE) {
- zone_start = vol->mft_lcn;
- if (!vol->mft_zone_end)
- zone_start = (ntfs_cluster_t)0;
- pass = 2;
- }
- if (zone == DATA_ZONE) {
- /* Skip searching the mft zone. */
- done_zones |= 1;
- if (zone_start >= vol->mft_zone_end) {
- zone_end = vol->nr_clusters;
- search_zone = 2;
- } else {
- zone_end = vol->mft_zone_start;
- search_zone = 4;
- }
- } else /* if (zone == MFT_ZONE) */ {
- zone_end = vol->mft_zone_end;
- search_zone = 1;
- }
- /*
- * buf_pos is the current bit position inside the bitmap. We use
- * initial_location to determine whether or not to do a zone switch.
- */
- buf_pos = initial_location = zone_start;
- /* Loop until all clusters are allocated, i.e. clusters == 0. */
- clusters = *count;
- rlpos = rlsize = 0;
- if (*count <= 0) {
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): *count <= 0, "
- "returning -EINVAL.\n");
- err = -EINVAL;
- goto err_ret;
- }
- while (1) {
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Start of outer while "
- "loop: done_zones = 0x%x, search_zone = %i, "
- "pass = %i, zone_start = 0x%x, zone_end = "
- "0x%x, initial_location = 0x%x, buf_pos = "
- "0x%x, rlpos = %i, rlsize = %i.\n",
- done_zones, search_zone, pass, zone_start,
- zone_end, initial_location, buf_pos, rlpos,
- rlsize);
- /* Loop until we run out of free clusters. */
- io.param = buf;
- io.size = PAGE_SIZE;
- io.do_read = 1;
- last_read_pos = buf_pos >> 3;
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): last_read_pos = "
- "0x%x.\n", last_read_pos);
- err = ntfs_readwrite_attr(vol->bitmap, data, last_read_pos,
- &io);
- if (err) {
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): "
- "ntfs_read_attr failed with error "
- "code %i, going to err_ret.\n", -err);
- goto err_ret;
- }
- if (!io.size) {
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): !io.size, "
- "going to zone_pass_done.\n");
- goto zone_pass_done;
- }
- buf_size = io.size << 3;
- lcn = buf_pos & 7;
- buf_pos &= ~7;
- need_writeback = 0;
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Before inner while "
- "loop: buf_size = 0x%x, lcn = 0x%x, buf_pos = "
- "0x%x, need_writeback = %i.\n", buf_size, lcn,
- buf_pos, need_writeback);
- while (lcn < buf_size && lcn + buf_pos < zone_end) {
- byte = buf + (lcn >> 3);
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): In inner "
- "while loop: buf_size = 0x%x, lcn = "
- "0x%x, buf_pos = 0x%x, need_writeback "
- "= %i, byte ofs = 0x%x, *byte = "
- "0x%x.\n", buf_size, lcn, buf_pos,
- need_writeback, lcn >> 3, *byte);
- /* Skip full bytes. */
- if (*byte == 0xff) {
- lcn += 8;
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): "
- "continuing while loop 1.\n");
- continue;
- }
- bit = 1 << (lcn & 7);
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): bit = %i.\n",
- bit);
- /* If the bit is already set, go onto the next one. */
- if (*byte & bit) {
- lcn++;
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): "
- "continuing while loop 2.\n");
- continue;
- }
- /* Allocate the bitmap bit. */
- *byte |= bit;
- /* We need to write this bitmap buffer back to disk! */
- need_writeback = 1;
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): *byte = "
- "0x%x, need_writeback = %i.\n", *byte,
- need_writeback);
- /* Reallocate memory if necessary. */
- if ((rlpos + 2) * sizeof(ntfs_runlist) >= rlsize) {
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): "
- "Reallocating space.\n");
- /* Setup first free bit return value. */
- if (!rl2) {
- *location = lcn + buf_pos;
- ntfs_debug(DEBUG_OTHER, __FUNCTION__
- "(): *location = "
- "0x%x.\n", *location);
- }
- rlsize += PAGE_SIZE;
- rlt = ntfs_vmalloc(rlsize);
- if (!rlt) {
- err = -ENOMEM;
- ntfs_debug(DEBUG_OTHER, __FUNCTION__
- "(): Failed to "
- "allocate memory, "
- "returning -ENOMEM, "
- "going to "
- "wb_err_ret.\n");
- goto wb_err_ret;
- }
- if (rl2) {
- ntfs_memcpy(rlt, rl2, rlsize -
- PAGE_SIZE);
- ntfs_vfree(rl2);
- }
- rl2 = rlt;
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): "
- "Reallocated memory, rlsize = "
- "0x%x.\n", rlsize);
- }
- /*
- * Coalesce with previous run if adjacent LCNs.
- * Otherwise, append a new run.
- */
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Adding run "
- "(lcn 0x%x, len 0x%x), prev_lcn = "
- "0x%x, lcn = 0x%x, buf_pos = 0x%x, "
- "prev_run_len = 0x%x, rlpos = %i.\n",
- lcn + buf_pos, 1, prev_lcn, lcn,
- buf_pos, prev_run_len, rlpos);
- if (prev_lcn == lcn + buf_pos - prev_run_len && rlpos) {
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): "
- "Coalescing to run (lcn 0x%x, "
- "len 0x%x).\n",
- rl2[rlpos - 1].lcn,
- rl2[rlpos - 1].len);
- rl2[rlpos - 1].len = ++prev_run_len;
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): "
- "Run now (lcn 0x%x, len 0x%x), "
- "prev_run_len = 0x%x.\n",
- rl2[rlpos - 1].lcn,
- rl2[rlpos - 1].len,
- prev_run_len);
- } else {
- if (rlpos)
- ntfs_debug(DEBUG_OTHER, __FUNCTION__
- "(): Adding new run, "
- "(previous run lcn "
- "0x%x, len 0x%x).\n",
- rl2[rlpos - 1].lcn,
- rl2[rlpos - 1].len);
- else
- ntfs_debug(DEBUG_OTHER, __FUNCTION__
- "(): Adding new run, "
- "is first run.\n");
- rl2[rlpos].lcn = prev_lcn = lcn + buf_pos;
- rl2[rlpos].len = prev_run_len =
- (ntfs_cluster_t)1;
-
- rlpos++;
- }
- /* Done? */
- if (!--clusters) {
- ntfs_cluster_t tc;
- /*
- * Update the current zone position. Positions
- * of already scanned zones have been updated
- * during the respective zone switches.
- */
- tc = lcn + buf_pos + 1;
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): "
- "Done. Updating current zone "
- "position, tc = 0x%x, "
- "search_zone = %i.\n", tc,
- search_zone);
- switch (search_zone) {
- case 1:
- ntfs_debug(DEBUG_OTHER, __FUNCTION__
- "(): Before checks, "
- "vol->mft_zone_pos = "
- "0x%x.\n",
- vol->mft_zone_pos);
- if (tc >= vol->mft_zone_end) {
- vol->mft_zone_pos =
- vol->mft_lcn;
- if (!vol->mft_zone_end)
- vol->mft_zone_pos =
- (ntfs_cluster_t)0;
- } else if ((initial_location >=
- vol->mft_zone_pos ||
- tc > vol->mft_zone_pos)
- && tc >= vol->mft_lcn)
- vol->mft_zone_pos = tc;
- ntfs_debug(DEBUG_OTHER, __FUNCTION__
- "(): After checks, "
- "vol->mft_zone_pos = "
- "0x%x.\n",
- vol->mft_zone_pos);
- break;
- case 2:
- ntfs_debug(DEBUG_OTHER, __FUNCTION__
- "(): Before checks, "
- "vol->data1_zone_pos = "
- "0x%x.\n",
- vol->data1_zone_pos);
- if (tc >= vol->nr_clusters)
- vol->data1_zone_pos =
- vol->mft_zone_end;
- else if ((initial_location >=
- vol->data1_zone_pos ||
- tc > vol->data1_zone_pos)
- && tc >= vol->mft_zone_end)
- vol->data1_zone_pos = tc;
- ntfs_debug(DEBUG_OTHER, __FUNCTION__
- "(): After checks, "
- "vol->data1_zone_pos = "
- "0x%x.\n",
- vol->data1_zone_pos);
- break;
- case 4:
- ntfs_debug(DEBUG_OTHER, __FUNCTION__
- "(): Before checks, "
- "vol->data2_zone_pos = "
- "0x%x.\n",
- vol->data2_zone_pos);
- if (tc >= vol->mft_zone_start)
- vol->data2_zone_pos =
- (ntfs_cluster_t)0;
- else if (initial_location >=
- vol->data2_zone_pos ||
- tc > vol->data2_zone_pos)
- vol->data2_zone_pos = tc;
- ntfs_debug(DEBUG_OTHER, __FUNCTION__
- "(): After checks, "
- "vol->data2_zone_pos = "
- "0x%x.\n",
- vol->data2_zone_pos);
- break;
- default:
- BUG();
- }
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): "
- "Going to done_ret.\n");
- goto done_ret;
- }
- lcn++;
- }
- buf_pos += buf_size;
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): After inner while "
- "loop: buf_size = 0x%x, lcn = 0x%x, buf_pos = "
- "0x%x, need_writeback = %i.\n", buf_size, lcn,
- buf_pos, need_writeback);
- if (need_writeback) {
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Writing "
- "back.\n");
- need_writeback = 0;
- io.param = buf;
- io.do_read = 0;
- err = ntfs_readwrite_attr(vol->bitmap, data,
- last_read_pos, &io);
- if (err) {
- ntfs_error(__FUNCTION__ "(): Bitmap writeback "
- "failed in read next buffer "
- "code path with error code "
- "%i.\n", -err);
- goto err_ret;
- }
- }
- if (buf_pos < zone_end) {
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Continuing "
- "outer while loop, buf_pos = 0x%x, "
- "zone_end = 0x%x.\n", buf_pos,
- zone_end);
- continue;
- }
-zone_pass_done: /* Finished with the current zone pass. */
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): At zone_pass_done, "
- "pass = %i.\n", pass);
- if (pass == 1) {
- /*
- * Now do pass 2, scanning the first part of the zone
- * we omitted in pass 1.
- */
- pass = 2;
- zone_end = zone_start;
- switch (search_zone) {
- case 1: /* mft_zone */
- zone_start = vol->mft_zone_start;
- break;
- case 2: /* data1_zone */
- zone_start = vol->mft_zone_end;
- break;
- case 4: /* data2_zone */
- zone_start = (ntfs_cluster_t)0;
- break;
- default:
- BUG();
- }
- /* Sanity check. */
- if (zone_end < zone_start)
- zone_end = zone_start;
- buf_pos = zone_start;
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Continuing "
- "outer while loop, pass = 2, "
- "zone_start = 0x%x, zone_end = 0x%x, "
- "buf_pos = 0x%x.\n");
- continue;
- } /* pass == 2 */
-done_zones_check:
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): At done_zones_check, "
- "search_zone = %i, done_zones before = 0x%x, "
- "done_zones after = 0x%x.\n",
- search_zone, done_zones, done_zones |
- search_zone);
- done_zones |= search_zone;
- if (done_zones < 7) {
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Switching "
- "zone.\n");
- /* Now switch to the next zone we haven't done yet. */
- pass = 1;
- switch (search_zone) {
- case 1:
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): "
- "Switching from mft zone to "
- "data1 zone.\n");
- /* Update mft zone position. */
- if (rlpos) {
- ntfs_cluster_t tc;
- ntfs_debug(DEBUG_OTHER, __FUNCTION__
- "(): Before checks, "
- "vol->mft_zone_pos = "
- "0x%x.\n",
- vol->mft_zone_pos);
- tc = rl2[rlpos - 1].lcn +
- rl2[rlpos - 1].len;
- if (tc >= vol->mft_zone_end) {
- vol->mft_zone_pos =
- vol->mft_lcn;
- if (!vol->mft_zone_end)
- vol->mft_zone_pos =
- (ntfs_cluster_t)0;
- } else if ((initial_location >=
- vol->mft_zone_pos ||
- tc > vol->mft_zone_pos)
- && tc >= vol->mft_lcn)
- vol->mft_zone_pos = tc;
- ntfs_debug(DEBUG_OTHER, __FUNCTION__
- "(): After checks, "
- "vol->mft_zone_pos = "
- "0x%x.\n",
- vol->mft_zone_pos);
- }
- /* Switch from mft zone to data1 zone. */
-switch_to_data1_zone: search_zone = 2;
- zone_start = initial_location =
- vol->data1_zone_pos;
- zone_end = vol->nr_clusters;
- if (zone_start == vol->mft_zone_end)
- pass = 2;
- if (zone_start >= zone_end) {
- vol->data1_zone_pos = zone_start =
- vol->mft_zone_end;
- pass = 2;
- }
- break;
- case 2:
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): "
- "Switching from data1 zone to "
- "data2 zone.\n");
- /* Update data1 zone position. */
- if (rlpos) {
- ntfs_cluster_t tc;
- ntfs_debug(DEBUG_OTHER, __FUNCTION__
- "(): Before checks, "
- "vol->data1_zone_pos = "
- "0x%x.\n",
- vol->data1_zone_pos);
- tc = rl2[rlpos - 1].lcn +
- rl2[rlpos - 1].len;
- if (tc >= vol->nr_clusters)
- vol->data1_zone_pos =
- vol->mft_zone_end;
- else if ((initial_location >=
- vol->data1_zone_pos ||
- tc > vol->data1_zone_pos)
- && tc >= vol->mft_zone_end)
- vol->data1_zone_pos = tc;
- ntfs_debug(DEBUG_OTHER, __FUNCTION__
- "(): After checks, "
- "vol->data1_zone_pos = "
- "0x%x.\n",
- vol->data1_zone_pos);
- }
- /* Switch from data1 zone to data2 zone. */
- search_zone = 4;
- zone_start = initial_location =
- vol->data2_zone_pos;
- zone_end = vol->mft_zone_start;
- if (!zone_start)
- pass = 2;
- if (zone_start >= zone_end) {
- vol->data2_zone_pos = zone_start =
- initial_location =
- (ntfs_cluster_t)0;
- pass = 2;
- }
- break;
- case 4:
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): "
- "Switching from data2 zone to "
- "data1 zone.\n");
- /* Update data2 zone position. */
- if (rlpos) {
- ntfs_cluster_t tc;
- ntfs_debug(DEBUG_OTHER, __FUNCTION__
- "(): Before checks, "
- "vol->data2_zone_pos = "
- "0x%x.\n",
- vol->data2_zone_pos);
- tc = rl2[rlpos - 1].lcn +
- rl2[rlpos - 1].len;
- if (tc >= vol->mft_zone_start)
- vol->data2_zone_pos =
- (ntfs_cluster_t)0;
- else if (initial_location >=
- vol->data2_zone_pos ||
- tc > vol->data2_zone_pos)
- vol->data2_zone_pos = tc;
- ntfs_debug(DEBUG_OTHER, __FUNCTION__
- "(): After checks, "
- "vol->data2_zone_pos = "
- "0x%x.\n",
- vol->data2_zone_pos);
- }
- /* Switch from data2 zone to data1 zone. */
- goto switch_to_data1_zone; /* See above. */
- default:
- BUG();
- }
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): After zone "
- "switch, search_zone = %i, pass = %i, "
- "initial_location = 0x%x, zone_start "
- "= 0x%x, zone_end = 0x%x.\n",
- search_zone, pass, initial_location,
- zone_start, zone_end);
- buf_pos = zone_start;
- if (zone_start == zone_end) {
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): "
- "Empty zone, going to "
- "done_zones_check.\n");
- /* Empty zone. Don't bother searching it. */
- goto done_zones_check;
- }
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Continuing "
- "outer while loop.\n");
- continue;
- } /* done_zones == 7 */
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): All zones are "
- "finished.\n");
- /*
- * All zones are finished! If DATA_ZONE, shrink mft zone. If
- * MFT_ZONE, we have really run out of space.
- */
- mft_zone_size = vol->mft_zone_end - vol->mft_zone_start;
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): vol->mft_zone_start "
- "= 0x%x, vol->mft_zone_end = 0x%x, "
- "mft_zone_size = 0x%x.\n", vol->mft_zone_start,
- vol->mft_zone_end, mft_zone_size);
- if (zone == MFT_ZONE || mft_zone_size <= (ntfs_cluster_t)0) {
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): No free "
- "clusters left, returning -ENOSPC, "
- "going to fail_ret.\n");
- /* Really no more space left on device. */
- err = -ENOSPC;
- goto fail_ret;
- } /* zone == DATA_ZONE && mft_zone_size > 0 */
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Shrinking mft "
- "zone.\n");
- zone_end = vol->mft_zone_end;
- mft_zone_size >>= 1;
- if (mft_zone_size > (ntfs_cluster_t)0)
- vol->mft_zone_end = vol->mft_zone_start + mft_zone_size;
- else /* mft zone and data2 zone no longer exist. */
- vol->data2_zone_pos = vol->mft_zone_start =
- vol->mft_zone_end = (ntfs_cluster_t)0;
- if (vol->mft_zone_pos >= vol->mft_zone_end) {
- vol->mft_zone_pos = vol->mft_lcn;
- if (!vol->mft_zone_end)
- vol->mft_zone_pos = (ntfs_cluster_t)0;
- }
- buf_pos = zone_start = initial_location =
- vol->data1_zone_pos = vol->mft_zone_end;
- search_zone = 2;
- pass = 2;
- done_zones &= ~2;
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): After shrinking mft "
- "zone, mft_zone_size = 0x%x, "
- "vol->mft_zone_start = 0x%x, vol->mft_zone_end "
- "= 0x%x, vol->mft_zone_pos = 0x%x, search_zone "
- "= 2, pass = 2, dones_zones = 0x%x, zone_start "
- "= 0x%x, zone_end = 0x%x, vol->data1_zone_pos "
- "= 0x%x, continuing outer while loop.\n",
- mft_zone_size, vol->mft_zone_start,
- vol->mft_zone_end, vol->mft_zone_pos,
- search_zone, pass, done_zones, zone_start,
- zone_end, vol->data1_zone_pos);
- }
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): After outer while loop.\n");
-done_ret:
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): At done_ret.\n");
- rl2[rlpos].lcn = (ntfs_cluster_t)-1;
- rl2[rlpos].len = (ntfs_cluster_t)0;
- *rl = rl2;
- *rl_len = rlpos;
- if (need_writeback) {
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Writing back.\n");
- need_writeback = 0;
- io.param = buf;
- io.do_read = 0;
- err = ntfs_readwrite_attr(vol->bitmap, data, last_read_pos,
- &io);
- if (err) {
- ntfs_error(__FUNCTION__ "(): Bitmap writeback failed "
- "in done code path with error code "
- "%i.\n", -err);
- goto err_ret;
- }
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Wrote 0x%Lx bytes.\n",
- io.size);
- }
-done_fail_ret:
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): At done_fail_ret (follows "
- "done_ret).\n");
- unlock_kernel();
- free_page((unsigned long)buf);
- if (err)
- ntfs_debug(DEBUG_FILE3, __FUNCTION__ "(): Failed to allocate "
- "clusters. Returning with error code %i.\n",
- -err);
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Syncing $Bitmap inode.\n");
- if (ntfs_update_inode(vol->bitmap))
- ntfs_error(__FUNCTION__ "(): Failed to sync inode $Bitmap. "
- "Continuing anyway.\n");
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Returning with code %i.\n",
- err);
- return err;
-fail_ret:
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): At fail_ret.\n");
- if (rl2) {
- if (err == -ENOSPC) {
- /* Return first free lcn and count of free clusters. */
- *location = rl2[0].lcn;
- *count -= clusters;
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): err = "
- "-ENOSPC, *location = 0x%x, *count = "
- "0x%x.\n", *location, *count);
- }
- /* Deallocate all allocated clusters. */
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Deallocating "
- "allocated clusters.\n");
- ntfs_deallocate_clusters(vol, rl2, rlpos);
- /* Free the runlist. */
- ntfs_vfree(rl2);
- } else {
- if (err == -ENOSPC) {
- /* Nothing free at all. */
- *location = vol->data1_zone_pos; /* Irrelevant... */
- *count = 0;
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): No space "
- "left at all, err = -ENOSPC, *location "
- "= 0x%x, *count = 0.\n", *location);
- }
- }
- *rl = NULL;
- *rl_len = 0;
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): *rl = NULL, *rl_len = 0, "
- "going to done_fail_ret.\n");
- goto done_fail_ret;
-wb_err_ret:
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): At wb_err_ret.\n");
- if (need_writeback) {
- int __err;
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Writing back.\n");
- io.param = buf;
- io.do_read = 0;
- __err = ntfs_readwrite_attr(vol->bitmap, data, last_read_pos,
- &io);
- if (__err)
- ntfs_error(__FUNCTION__ "(): Bitmap writeback failed "
- "in error code path with error code "
- "%i.\n", -__err);
- need_writeback = 0;
- }
-err_ret:
- ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): At err_ret, *location = -1, "
- "*count = 0, going to fail_ret.\n");
- *location = -1;
- *count = 0;
- goto fail_ret;
-}
-
-/*
- * IMPORTANT: Caller has to hold big kernel lock or the race monster will come
- * to get you! (-;
- * TODO: Need our own lock for bitmap accesses but BKL is more secure for now,
- * considering we might not have covered all places with a lock yet. In that
- * case the BKL offers a one way exclusion which is better than no exclusion
- * at all... (AIA)
- */
-static int ntfs_clear_bitrange(ntfs_inode *bitmap,
- const ntfs_cluster_t start_bit, const ntfs_cluster_t count)
-{
- ntfs_cluster_t buf_size, bit, nr_bits = count;
- unsigned char *buf, *byte;
- int err;
- ntfs_io io;
-
- io.fn_put = ntfs_put;
- io.fn_get = ntfs_get;
- /* Calculate the required buffer size in bytes. */
- buf_size = (ntfs_cluster_t)((start_bit & 7) + nr_bits + 7) >> 3;
- if (buf_size <= (ntfs_cluster_t)(64 * 1024))
- buf = ntfs_malloc(buf_size);
- else
- buf = ntfs_vmalloc(buf_size);
- if (!buf)
- return -ENOMEM;
- /* Read the bitmap from the data attribute. */
- io.param = byte = buf;
- io.size = buf_size;
- err = ntfs_read_attr(bitmap, bitmap->vol->at_data, 0, start_bit >> 3,
- &io);
- if (err || io.size != buf_size)
- goto err_out;
- /* Now clear the bits in the read bitmap. */
- bit = start_bit & 7;
- while (bit && nr_bits) { /* Process first partial byte, if present. */
- *byte &= ~(1 << bit++);
- nr_bits--;
- bit &= 7;
- if (!bit)
- byte++;
- }
- while (nr_bits >= 8) { /* Process full bytes. */
- *byte = 0;
- nr_bits -= 8;
- byte++;
- }
- bit = 0;
- while (nr_bits) { /* Process last partial byte, if present. */
- *byte &= ~(1 << bit);
- nr_bits--;
- bit++;
- }
- /* Write the modified bitmap back to disk. */
- io.param = buf;
- io.size = buf_size;
- err = ntfs_write_attr(bitmap, bitmap->vol->at_data, 0, start_bit >> 3,
- &io);
-err_out:
- if (buf_size <= (ntfs_cluster_t)(64 * 1024))
- ntfs_free(buf);
- else
- ntfs_vfree(buf);
- if (!err && io.size != buf_size)
- err = -EIO;
- return err;
-}
-
-/*
- * See comments for lack of zone adjustments below in the description of the
- * function ntfs_deallocate_clusters().
- */
-int ntfs_deallocate_cluster_run(const ntfs_volume *vol,
- const ntfs_cluster_t lcn, const ntfs_cluster_t len)
-{
- int err;
-
- lock_kernel();
- err = ntfs_clear_bitrange(vol->bitmap, lcn, len);
- unlock_kernel();
- return err;
-}
-
-/*
- * This is inefficient, but logically trivial, so will do for now. Note, we
- * do not touch the mft nor the data zones here because we want to minimize
- * recycling of clusters to enhance the chances of data being undeleteable.
- * Also we don't want the overhead. Instead we do one additional sweep of the
- * current data zone during cluster allocation to check for freed clusters.
- */
-int ntfs_deallocate_clusters(const ntfs_volume *vol, const ntfs_runlist *rl,
- const int rl_len)
-{
- int i, err;
-
- lock_kernel();
- for (i = err = 0; i < rl_len && !err; i++)
- err = ntfs_clear_bitrange(vol->bitmap, rl[i].lcn, rl[i].len);
- unlock_kernel();
- return err;
-}
-
diff --git a/fs/ntfs/super.h b/fs/ntfs/super.h
deleted file mode 100644
index a974a5f46340..000000000000
--- a/fs/ntfs/super.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * super.h - Header file for super.c
- *
- * Copyright (C) 1995-1997 Martin von Löwis
- * Copyright (C) 1996-1997 Régis Duchesne
- * Copyright (c) 2001 Anton Altaparmakov
- */
-
-int ntfs_get_free_cluster_count(ntfs_inode *bitmap);
-
-int ntfs_get_volumesize(ntfs_volume *vol, __s64 *vol_size);
-
-int ntfs_init_volume(ntfs_volume *vol, char *boot);
-
-int ntfs_load_special_files(ntfs_volume *vol);
-
-int ntfs_release_volume(ntfs_volume *vol);
-
-int ntfs_insert_fixups(unsigned char *rec, int rec_size);
-
-int ntfs_fixup_record(char *record, char *magic, int size);
-
-int ntfs_allocate_clusters(ntfs_volume *vol, ntfs_cluster_t *location,
- ntfs_cluster_t *count, ntfs_runlist **rl, int *rl_len,
- const NTFS_CLUSTER_ALLOCATION_ZONES zone);
-
-int ntfs_deallocate_cluster_run(const ntfs_volume *vol,
- const ntfs_cluster_t lcn, const ntfs_cluster_t len);
-
-int ntfs_deallocate_clusters(const ntfs_volume *vol, const ntfs_runlist *rl,
- const int rl_len);
-
diff --git a/fs/ntfs/support.c b/fs/ntfs/support.c
deleted file mode 100644
index 025c09cc83f3..000000000000
--- a/fs/ntfs/support.c
+++ /dev/null
@@ -1,316 +0,0 @@
-/*
- * support.c - Specific support functions
- *
- * Copyright (C) 1997 Martin von Löwis
- * Copyright (C) 1997 Régis Duchesne
- * Copyright (C) 2001 Anton Altaparmakov (AIA)
- */
-
-#include "ntfstypes.h"
-#include "struct.h"
-#include "support.h"
-
-#include <stdarg.h>
-#include <linux/slab.h>
-#include <linux/locks.h>
-#include <linux/fs.h>
-#include "util.h"
-#include "inode.h"
-#include "macros.h"
-#include <linux/nls.h>
-
-static char print_buf[1024];
-
-#ifdef DEBUG
-#include "sysctl.h"
-#include <linux/kernel.h>
-
-/* Debugging output */
-void ntfs_debug(int mask, const char *fmt, ...)
-{
- va_list ap;
-
- /* Filter it with the debugging level required */
- if (ntdebug & mask) {
- va_start(ap,fmt);
- strcpy(print_buf, KERN_DEBUG "NTFS: ");
- vsprintf(print_buf + 9, fmt, ap);
- printk(print_buf);
- va_end(ap);
- }
-}
-
-#ifndef ntfs_malloc
-/* Verbose kmalloc */
-void *ntfs_malloc(int size)
-{
- void *ret;
-
- ret = kmalloc(size, GFP_KERNEL);
- ntfs_debug(DEBUG_MALLOC, "Allocating %x at %p\n", size, ret);
-
- return ret;
-}
-#endif
-
-#ifndef ntfs_free
-/* Verbose kfree() */
-void ntfs_free(void *block)
-{
- ntfs_debug(DEBUG_MALLOC, "Freeing memory at %p\n", block);
- kfree(block);
-}
-#endif
-#else /* End of DEBUG functions. Normal ones below... */
-
-#ifndef ntfs_malloc
-void *ntfs_malloc(int size)
-{
- return kmalloc(size, GFP_KERNEL);
-}
-#endif
-
-#ifndef ntfs_free
-void ntfs_free(void *block)
-{
- kfree(block);
-}
-#endif
-#endif /* DEBUG */
-
-void ntfs_bzero(void *s, int n)
-{
- memset(s, 0, n);
-}
-
-/* These functions deliberately return no value. It is dest, anyway,
- and not used anywhere in the NTFS code. */
-
-void ntfs_memcpy(void *dest, const void *src, ntfs_size_t n)
-{
- memcpy(dest, src, n);
-}
-
-void ntfs_memmove(void *dest, const void *src, ntfs_size_t n)
-{
- memmove(dest, src, n);
-}
-
-/* Warn that an error occurred. */
-void ntfs_error(const char *fmt,...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- strcpy(print_buf, KERN_ERR "NTFS: ");
- vsprintf(print_buf + 9, fmt, ap);
- printk(print_buf);
- va_end(ap);
-}
-
-int ntfs_read_mft_record(ntfs_volume *vol, int mftno, char *buf)
-{
- int error;
- ntfs_io io;
-
- ntfs_debug(DEBUG_OTHER, "read_mft_record 0x%x\n", mftno);
- if (mftno == FILE_Mft)
- {
- ntfs_memcpy(buf, vol->mft, vol->mft_record_size);
- return 0;
- }
- if (!vol->mft_ino)
- {
- printk(KERN_ERR "NTFS: mft_ino is NULL. Something is terribly "
- "wrong here!\n");
- return -ENODATA;
- }
- io.fn_put = ntfs_put;
- io.fn_get = 0;
- io.param = buf;
- io.size = vol->mft_record_size;
- ntfs_debug(DEBUG_OTHER, "read_mft_record: calling ntfs_read_attr with: "
- "mftno = 0x%x, vol->mft_record_size_bits = 0x%x, "
- "mftno << vol->mft_record_size_bits = 0x%Lx\n", mftno,
- vol->mft_record_size_bits,
- (__s64)mftno << vol->mft_record_size_bits);
- error = ntfs_read_attr(vol->mft_ino, vol->at_data, NULL,
- (__s64)mftno << vol->mft_record_size_bits, &io);
- if (error || (io.size != vol->mft_record_size)) {
- ntfs_debug(DEBUG_OTHER, "read_mft_record: read 0x%x failed "
- "(%d,%d,%d)\n", mftno, error, io.size,
- vol->mft_record_size);
- return error ? error : -ENODATA;
- }
- ntfs_debug(DEBUG_OTHER, "read_mft_record: finished read 0x%x\n", mftno);
- if (!ntfs_check_mft_record(vol, buf)) {
- /* FIXME: This is incomplete behaviour. We might be able to
- * recover at this stage. ntfs_check_mft_record() is too
- * conservative at aborting it's operations. It is OK for
- * now as we just can't handle some on disk structures
- * this way. (AIA) */
- printk(KERN_WARNING "NTFS: Invalid MFT record for 0x%x\n", mftno);
- return -EIO;
- }
- ntfs_debug(DEBUG_OTHER, "read_mft_record: Done 0x%x\n", mftno);
- return 0;
-}
-
-int ntfs_getput_clusters(ntfs_volume *vol, int cluster, ntfs_size_t start_offs,
- ntfs_io *buf)
-{
- struct super_block *sb = NTFS_SB(vol);
- struct buffer_head *bh;
- int length = buf->size;
- int error = 0;
- ntfs_size_t to_copy;
-
- ntfs_debug(DEBUG_OTHER, "%s_clusters %d %d %d\n",
- buf->do_read ? "get" : "put", cluster, start_offs, length);
- to_copy = vol->cluster_size - start_offs;
- while (length) {
- if (!(bh = sb_bread(sb, cluster))) {
- ntfs_debug(DEBUG_OTHER, "%s failed\n",
- buf->do_read ? "Reading" : "Writing");
- error = -EIO;
- goto error_ret;
- }
- if (to_copy > length)
- to_copy = length;
- lock_buffer(bh);
- if (buf->do_read) {
- buf->fn_put(buf, bh->b_data + start_offs, to_copy);
- unlock_buffer(bh);
- } else {
- buf->fn_get(bh->b_data + start_offs, buf, to_copy);
- mark_buffer_dirty(bh);
- unlock_buffer(bh);
- /*
- * Note: We treat synchronous IO on a per volume basis
- * disregarding flags of individual inodes. This can
- * lead to some strange write ordering effects upon a
- * remount with a change in the sync flag but it should
- * not break anything. [Except if the system crashes
- * at that point in time but there would be more thigs
- * to worry about than that in that case...]. (AIA)
- */
- if (sb->s_flags & MS_SYNCHRONOUS) {
- ll_rw_block(WRITE, 1, &bh);
- wait_on_buffer(bh);
- if (buffer_req(bh) && !buffer_uptodate(bh)) {
- printk(KERN_ERR "IO error syncing NTFS "
- "cluster [%s:%i]\n",
- sb->s_id, cluster);
- brelse(bh);
- error = -EIO;
- goto error_ret;
- }
- }
- }
- brelse(bh);
- length -= to_copy;
- start_offs = 0;
- to_copy = vol->cluster_size;
- cluster++;
- }
-error_ret:
- return error;
-}
-
-ntfs_time64_t ntfs_now(void)
-{
- return ntfs_unixutc2ntutc(CURRENT_TIME);
-}
-
-int ntfs_dupuni2map(ntfs_volume *vol, ntfs_u16 *in, int in_len, char **out,
- int *out_len)
-{
- int i, o, chl, chi;
- char *result, *buf, charbuf[NLS_MAX_CHARSET_SIZE];
- struct nls_table *nls = vol->nls_map;
-
- result = ntfs_malloc(in_len + 1);
- if (!result)
- return -ENOMEM;
- *out_len = in_len;
- for (i = o = 0; i < in_len; i++) {
- /* FIXME: Byte order? */
- wchar_t uni = in[i];
- if ((chl = nls->uni2char(uni, charbuf,
- NLS_MAX_CHARSET_SIZE)) > 0) {
- /* Adjust result buffer. */
- if (chl > 1) {
- buf = ntfs_malloc(*out_len + chl - 1);
- if (!buf) {
- i = -ENOMEM;
- goto err_ret;
- }
- memcpy(buf, result, o);
- ntfs_free(result);
- result = buf;
- *out_len += (chl - 1);
- }
- for (chi = 0; chi < chl; chi++)
- result[o++] = charbuf[chi];
- } else {
- /* Invalid character. */
- printk(KERN_ERR "NTFS: Unicode name contains a "
- "character that cannot be converted "
- "to chosen character set. Remount "
- "with utf8 encoding and this should "
- "work.\n");
- i = -EILSEQ;
- goto err_ret;
- }
- }
- result[*out_len] = '\0';
- *out = result;
- return 0;
-err_ret:
- ntfs_free(result);
- *out_len = 0;
- *out = NULL;
- return i;
-}
-
-int ntfs_dupmap2uni(ntfs_volume *vol, char* in, int in_len, ntfs_u16 **out,
- int *out_len)
-{
- int i, o;
- ntfs_u16 *result;
- struct nls_table *nls = vol->nls_map;
-
- *out = result = ntfs_malloc(2 * in_len);
- if (!result) {
- *out_len = 0;
- return -ENOMEM;
- }
- *out_len = in_len;
- for (i = o = 0; i < in_len; i++, o++) {
- wchar_t uni;
- int charlen;
-
- charlen = nls->char2uni(&in[i], in_len - i, &uni);
- if (charlen < 0) {
- i = charlen;
- goto err_ret;
- }
- *out_len -= charlen - 1;
- i += charlen - 1;
- /* FIXME: Byte order? */
- result[o] = uni;
- if (!result[o]) {
- i = -EILSEQ;
- goto err_ret;
- }
- }
- return 0;
-err_ret:
- printk(KERN_ERR "NTFS: Name contains a character that cannot be "
- "converted to Unicode.\n");
- ntfs_free(result);
- *out_len = 0;
- *out = NULL;
- return i;
-}
-
diff --git a/fs/ntfs/support.h b/fs/ntfs/support.h
deleted file mode 100644
index c2381e03e899..000000000000
--- a/fs/ntfs/support.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * support.h - Header file for specific support.c
- *
- * Copyright (C) 1997 Régis Duchesne
- * Copyright (c) 2001 Anton Altaparmakov (AIA)
- */
-
-/* Debug levels */
-#define DEBUG_OTHER 1
-#define DEBUG_MALLOC 2
-#define DEBUG_BSD 4
-#define DEBUG_LINUX 8
-#define DEBUG_DIR1 16
-#define DEBUG_DIR2 32
-#define DEBUG_DIR3 64
-#define DEBUG_FILE1 128
-#define DEBUG_FILE2 256
-#define DEBUG_FILE3 512
-#define DEBUG_NAME1 1024
-#define DEBUG_NAME2 2048
-
-#ifdef DEBUG
-void ntfs_debug(int mask, const char *fmt, ...);
-#else
-#define ntfs_debug(mask, fmt...) do {} while (0)
-#endif
-
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-
-#define ntfs_malloc(size) kmalloc(size, GFP_KERNEL)
-
-#define ntfs_free(ptr) kfree(ptr)
-
-#define ntfs_vmalloc(size) vmalloc_32(size)
-
-#define ntfs_vfree(ptr) vfree(ptr)
-
-void ntfs_bzero(void *s, int n);
-
-void ntfs_memcpy(void *dest, const void *src, ntfs_size_t n);
-
-void ntfs_memmove(void *dest, const void *src, ntfs_size_t n);
-
-void ntfs_error(const char *fmt,...);
-
-int ntfs_read_mft_record(ntfs_volume *vol, int mftno, char *buf);
-
-int ntfs_getput_clusters(ntfs_volume *pvol, int cluster, ntfs_size_t offs,
- ntfs_io *buf);
-
-ntfs_time64_t ntfs_now(void);
-
-int ntfs_dupuni2map(ntfs_volume *vol, ntfs_u16 *in, int in_len, char **out,
- int *out_len);
-
-int ntfs_dupmap2uni(ntfs_volume *vol, char* in, int in_len, ntfs_u16 **out,
- int *out_len);
-
diff --git a/fs/ntfs/sysctl.c b/fs/ntfs/sysctl.c
deleted file mode 100644
index 8d5807d5da31..000000000000
--- a/fs/ntfs/sysctl.c
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * sysctl.c - System control stuff
- *
- * Copyright (C) 1997 Martin von Löwis
- * Copyright (C) 1997 Régis Duchesne
- */
-
-#include "sysctl.h"
-
-#ifdef DEBUG
-#include <linux/locks.h>
-#include <linux/sysctl.h>
-
-int ntdebug = 0;
-
-/* Add or remove the debug sysctl
- * Is this really the only file system with sysctls ?
- */
-void ntfs_sysctl(int add)
-{
-#define FS_NTFS 1
- /* Definition of the sysctl */
- static ctl_table ntfs_sysctls[]={
- {FS_NTFS, /* ID */
- "ntfs-debug", /* name in /proc */
- &ntdebug,sizeof(ntdebug), /* data ptr, data size */
- 0644, /* mode */
- 0, /* child */
- proc_dointvec, /* proc handler */
- 0, /* strategy */
- 0, /* proc control block */
- 0,0}, /* extra */
- {0}
- };
- /* Define the parent file : /proc/sys/fs */
- static ctl_table sysctls_root[]={
- {CTL_FS,
- "fs",
- NULL,0,
- 0555,
- ntfs_sysctls},
- {0}
- };
- static struct ctl_table_header *sysctls_root_header = NULL;
-
- if(add){
- if(!sysctls_root_header)
- sysctls_root_header = register_sysctl_table(sysctls_root, 0);
- } else if(sysctls_root_header) {
- unregister_sysctl_table(sysctls_root_header);
- sysctls_root_header = NULL;
- }
-}
-#endif /* DEBUG */
-
diff --git a/fs/ntfs/sysctl.h b/fs/ntfs/sysctl.h
deleted file mode 100644
index e10481b58d21..000000000000
--- a/fs/ntfs/sysctl.h
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * sysctl.h - Header file for sysctl.c
- *
- * Copyright (C) 1997 Martin von Löwis
- * Copyright (C) 1997 Régis Duchesne
- */
-
-#ifdef DEBUG
- extern int ntdebug;
-
- void ntfs_sysctl(int add);
-
- #define SYSCTL(x) ntfs_sysctl(x)
-#else
- #define SYSCTL(x)
-#endif /* DEBUG */
-
diff --git a/fs/ntfs/unistr.c b/fs/ntfs/unistr.c
deleted file mode 100644
index c86d9b0622a7..000000000000
--- a/fs/ntfs/unistr.c
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * unistr.c - Unicode string handling. Part of the Linux-NTFS project.
- *
- * Copyright (c) 2000,2001 Anton Altaparmakov.
- *
- * This program/include file is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program/include file is distributed in the hope that it will be
- * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program (in the main directory of the 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 <linux/string.h>
-#include <linux/fs.h>
-#include <asm/byteorder.h>
-
-#include "unistr.h"
-#include "macros.h"
-
-/*
- * This is used by the name collation functions to quickly determine what
- * characters are (in)valid.
- */
-const __u8 legal_ansi_char_array[0x40] = {
- 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
- 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
-
- 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
- 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
-
- 0x17, 0x07, 0x18, 0x17, 0x17, 0x17, 0x17, 0x17,
- 0x17, 0x17, 0x18, 0x16, 0x16, 0x17, 0x07, 0x00,
-
- 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17,
- 0x17, 0x17, 0x04, 0x16, 0x18, 0x16, 0x18, 0x18,
-};
-
-/**
- * ntfs_are_names_equal - compare two Unicode names for equality
- * @s1: name to compare to @s2
- * @s1_len: length in Unicode characters of @s1
- * @s2: name to compare to @s1
- * @s2_len: length in Unicode characters of @s2
- * @ic: ignore case bool
- * @upcase: upcase table (only if @ic == IGNORE_CASE)
- * @upcase_size: length in Unicode characters of @upcase (if present)
- *
- * Compare the names @s1 and @s2 and return TRUE (1) if the names are
- * identical, or FALSE (0) if they are not identical. If @ic is IGNORE_CASE,
- * the @upcase table is used to performa a case insensitive comparison.
- */
-int ntfs_are_names_equal(wchar_t *s1, size_t s1_len,
- wchar_t *s2, size_t s2_len, int ic,
- wchar_t *upcase, __u32 upcase_size)
-{
- if (s1_len != s2_len)
- return 0;
- if (!ic)
- return memcmp(s1, s2, s1_len << 1) ? 0: 1;
- return ntfs_wcsncasecmp(s1, s2, s1_len, upcase, upcase_size) ? 0: 1;
-}
-
-/**
- * ntfs_collate_names - collate two Unicode names
- * @upcase: upcase table (ignored if @ic is CASE_SENSITIVE)
- * @upcase_len: upcase table size (ignored if @ic is CASE_SENSITIVE)
- * @name1: first Unicode name to compare
- * @name2: second Unicode name to compare
- * @ic: either CASE_SENSITIVE or IGNORE_CASE
- * @err_val: if @name1 contains an invalid character return this value
- *
- * ntfs_collate_names collates two Unicode names and returns:
- *
- * -1 if the first name collates before the second one,
- * 0 if the names match,
- * 1 if the second name collates before the first one, or
- * @ec if an invalid character is encountered in @name1 during the comparison.
- *
- * The following characters are considered invalid: '"', '*', '<', '>' and '?'.
- */
-int ntfs_collate_names(wchar_t *upcase, __u32 upcase_len,
- wchar_t *name1, __u32 name1_len,
- wchar_t *name2, __u32 name2_len,
- int ic, int err_val)
-{
- __u32 cnt, min_len;
- wchar_t c1, c2;
-
- min_len = name1_len;
- if (min_len > name2_len)
- min_len = name2_len;
- for (cnt = 0; cnt < min_len; ++cnt) {
- c1 = le16_to_cpu(*name1++);
- c2 = le16_to_cpu(*name2++);
- if (ic) {
- if (c1 < upcase_len)
- c1 = le16_to_cpu(upcase[c1]);
- if (c2 < upcase_len)
- c2 = le16_to_cpu(upcase[c2]);
- }
- if (c1 < 64 && legal_ansi_char_array[c1] & 8)
- return err_val;
- if (c1 < c2)
- return -1;
- if (c1 > c2)
- return 1;
- ++name1;
- ++name2;
- }
- if (name1_len < name2_len)
- return -1;
- if (name1_len == name2_len)
- return 0;
- /* name1_len > name2_len */
- c1 = le16_to_cpu(*name1);
- if (c1 < 64 && legal_ansi_char_array[c1] & 8)
- return err_val;
- return 1;
-}
-
-/**
- * ntfs_wcsncasecmp - compare two little endian Unicode strings, ignoring case
- * @s1: first string
- * @s2: second string
- * @n: maximum unicode characters to compare
- * @upcase: upcase table
- * @upcase_size: upcase table size in Unicode characters
- *
- * Compare the first @n characters of the Unicode strings @s1 and @s2,
- * ignoring case. The strings in little endian format and appropriate
- * le16_to_cpu() conversion is performed on non-little endian machines.
- *
- * Each character is uppercased using the @upcase table before the comparison.
- *
- * The function returns an integer less than, equal to, or greater than zero
- * if @s1 (or the first @n Unicode characters thereof) is found, respectively,
- * to be less than, to match, or be greater than @s2.
- */
-int ntfs_wcsncasecmp(wchar_t *s1, wchar_t *s2, size_t n,
- wchar_t *upcase, __u32 upcase_size)
-{
- wchar_t c1, c2;
- size_t i;
-
- for (i = 0; i < n; ++i) {
- if ((c1 = le16_to_cpu(s1[i])) < upcase_size)
- c1 = le16_to_cpu(upcase[c1]);
- if ((c2 = le16_to_cpu(s2[i])) < upcase_size)
- c2 = le16_to_cpu(upcase[c2]);
- if (c1 < c2)
- return -1;
- if (c1 > c2)
- return 1;
- if (!c1)
- break;
- }
- return 0;
-}
-
diff --git a/fs/ntfs/unistr.h b/fs/ntfs/unistr.h
deleted file mode 100644
index 8b546d137865..000000000000
--- a/fs/ntfs/unistr.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * unistr.h - Exports for unicode string handling. Part of the Linux-NTFS
- * project.
- *
- * Copyright (c) 2000,2001 Anton Altaparmakov.
- *
- * This program/include file is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program/include file is distributed in the hope that it will be
- * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program (in the main directory of the 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 _LINUX_NTFS_UNISTR_H
-#define _LINUX_NTFS_UNISTR_H
-
-#include <linux/types.h>
-#include <linux/nls.h>
-
-extern const __u8 legal_ansi_char_array[0x40];
-
-int ntfs_are_names_equal(wchar_t *s1, size_t s1_len,
- wchar_t *s2, size_t s2_len, int ic,
- wchar_t *upcase, __u32 upcase_size);
-
-int ntfs_collate_names(wchar_t *upcase, __u32 upcase_len,
- wchar_t *name1, __u32 name1_len,
- wchar_t *name2, __u32 name2_len,
- int ic, int err_val);
-
-int ntfs_wcsncasecmp(wchar_t *s1, wchar_t *s2, size_t n,
- wchar_t *upcase, __u32 upcase_size);
-
-#endif /* defined _LINUX_NTFS_UNISTR_H */
-
diff --git a/fs/ntfs/util.c b/fs/ntfs/util.c
deleted file mode 100644
index 082e1b7d788e..000000000000
--- a/fs/ntfs/util.c
+++ /dev/null
@@ -1,265 +0,0 @@
-/*
- * util.c - Miscellaneous support
- *
- * Copyright (C) 1997,1999 Martin von Löwis
- * Copyright (C) 1997 Régis Duchesne
- * Copyright (C) 2001 Anton Altaparmakov (AIA)
- *
- * The utf8 routines are copied from Python wstrop module.
- */
-
-#include "ntfstypes.h"
-#include "struct.h"
-#include "util.h"
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <asm/div64.h> /* For do_div(). */
-#include "support.h"
-
-/*
- * Converts a single wide character to a sequence of utf8 bytes.
- * The character is represented in host byte order.
- * Returns the number of bytes, or 0 on error.
- */
-static int to_utf8(ntfs_u16 c, unsigned char *buf)
-{
- if (c == 0)
- return 0; /* No support for embedded 0 runes. */
- if (c < 0x80) {
- if (buf)
- buf[0] = (unsigned char)c;
- return 1;
- }
- if (c < 0x800) {
- if (buf) {
- buf[0] = 0xc0 | (c >> 6);
- buf[1] = 0x80 | (c & 0x3f);
- }
- return 2;
- }
- /* c < 0x10000 */
- if (buf) {
- buf[0] = 0xe0 | (c >> 12);
- buf[1] = 0x80 | ((c >> 6) & 0x3f);
- buf[2] = 0x80 | (c & 0x3f);
- }
- return 3;
-}
-
-/*
- * Decodes a sequence of utf8 bytes into a single wide character.
- * The character is returned in host byte order.
- * Returns the number of bytes consumed, or 0 on error.
- */
-static int from_utf8(const unsigned char *str, ntfs_u16 *c)
-{
- int l = 0, i;
-
- if (*str < 0x80) {
- *c = *str;
- return 1;
- }
- if (*str < 0xc0) /* Lead byte must not be 10xxxxxx. */
- return 0; /* Is c0 a possible lead byte? */
- if (*str < 0xe0) { /* 110xxxxx */
- *c = *str & 0x1f;
- l = 2;
- } else if (*str < 0xf0) { /* 1110xxxx */
- *c = *str & 0xf;
- l = 3;
- } else if (*str < 0xf8) { /* 11110xxx */
- *c = *str & 7;
- l = 4;
- } else /* We don't support characters above 0xFFFF in NTFS. */
- return 0;
- for (i = 1; i < l; i++) {
- /* All other bytes must be 10xxxxxx. */
- if ((str[i] & 0xc0) != 0x80)
- return 0;
- *c <<= 6;
- *c |= str[i] & 0x3f;
- }
- return l;
-}
-
-/*
- * Converts wide string to UTF-8. Expects two in- and two out-parameters.
- * Returns 0 on success, or error code.
- * The caller has to free the result string.
- */
-static int ntfs_dupuni2utf8(ntfs_u16 *in, int in_len, char **out, int *out_len)
-{
- int i, tmp;
- int len8;
- unsigned char *result;
-
- ntfs_debug(DEBUG_NAME1, "converting l = %d\n", in_len);
- /* Count the length of the resulting UTF-8. */
- for (i = len8 = 0; i < in_len; i++) {
- tmp = to_utf8(NTFS_GETU16(in + i), 0);
- if (!tmp)
- /* Invalid character. */
- return -EILSEQ;
- len8 += tmp;
- }
- *out = result = ntfs_malloc(len8 + 1); /* allow for zero-termination */
- if (!result)
- return -ENOMEM;
- result[len8] = '\0';
- *out_len = len8;
- for (i = len8 = 0; i < in_len; i++)
- len8 += to_utf8(NTFS_GETU16(in + i), result + len8);
- ntfs_debug(DEBUG_NAME1, "result %p:%s\n", result, result);
- return 0;
-}
-
-/*
- * Converts an UTF-8 sequence to a wide string. Same conventions as the
- * previous function.
- */
-static int ntfs_duputf82uni(unsigned char* in, int in_len, ntfs_u16** out,
- int *out_len)
-{
- int i, tmp;
- int len16;
- ntfs_u16* result;
- ntfs_u16 wtmp;
-
- for (i = len16 = 0; i < in_len; i += tmp, len16++) {
- tmp = from_utf8(in + i, &wtmp);
- if (!tmp)
- return -EILSEQ;
- }
- *out = result = ntfs_malloc(2 * (len16 + 1));
- if (!result)
- return -ENOMEM;
- result[len16] = 0;
- *out_len = len16;
- for (i = len16 = 0; i < in_len; i += tmp, len16++) {
- tmp = from_utf8(in + i, &wtmp);
- NTFS_PUTU16(result + len16, wtmp);
- }
- return 0;
-}
-
-/* Encodings dispatchers. */
-int ntfs_encodeuni(ntfs_volume *vol, ntfs_u16 *in, int in_len, char **out,
- int *out_len)
-{
- if (vol->nls_map)
- return ntfs_dupuni2map(vol, in, in_len, out, out_len);
- else
- return ntfs_dupuni2utf8(in, in_len, out, out_len);
-}
-
-int ntfs_decodeuni(ntfs_volume *vol, char *in, int in_len, ntfs_u16 **out,
- int *out_len)
-{
- if (vol->nls_map)
- return ntfs_dupmap2uni(vol, in, in_len, out, out_len);
- else
- return ntfs_duputf82uni(in, in_len, out, out_len);
-}
-
-/* Same address space copies. */
-void ntfs_put(ntfs_io *dest, void *src, ntfs_size_t n)
-{
- ntfs_memcpy(dest->param, src, n);
- ((char*)dest->param) += n;
-}
-
-void ntfs_get(void* dest, ntfs_io *src, ntfs_size_t n)
-{
- ntfs_memcpy(dest, src->param, n);
- ((char*)src->param) += n;
-}
-
-void *ntfs_calloc(int size)
-{
- void *result = ntfs_malloc(size);
- if (result)
- ntfs_bzero(result, size);
- return result;
-}
-
-/* Copy len ascii characters from from to to. :) */
-void ntfs_ascii2uni(short int *to, char *from, int len)
-{
- int i;
-
- for (i = 0; i < len; i++)
- NTFS_PUTU16(to + i, from[i]);
- to[i] = 0;
-}
-
-/* strncmp for Unicode strings. */
-int ntfs_uni_strncmp(short int* a, short int *b, int n)
-{
- int i;
-
- for(i = 0; i < n; i++)
- {
- if (NTFS_GETU16(a + i) < NTFS_GETU16(b + i))
- return -1;
- if (NTFS_GETU16(b + i) < NTFS_GETU16(a + i))
- return 1;
- if (NTFS_GETU16(a + i) == 0)
- break;
- }
- return 0;
-}
-
-/* strncmp between Unicode and ASCII strings. */
-int ntfs_ua_strncmp(short int* a, char* b, int n)
-{
- int i;
-
- for (i = 0; i < n; i++) {
- if(NTFS_GETU16(a + i) < b[i])
- return -1;
- if(b[i] < NTFS_GETU16(a + i))
- return 1;
- if (b[i] == 0)
- return 0;
- }
- return 0;
-}
-
-#define NTFS_TIME_OFFSET ((ntfs_time64_t)(369*365 + 89) * 24 * 3600 * 10000000)
-
-/* Convert the NT UTC (based 1.1.1601, in hundred nanosecond units)
- * into Unix UTC (based 1.1.1970, in seconds). */
-ntfs_time_t ntfs_ntutc2unixutc(ntfs_time64_t ntutc)
-{
- /* Subtract the NTFS time offset, then convert to 1s intervals. */
- ntfs_time64_t t = ntutc - NTFS_TIME_OFFSET;
- do_div(t, 10000000);
- return (ntfs_time_t)t;
-}
-
-/* Convert the Unix UTC into NT UTC. */
-ntfs_time64_t ntfs_unixutc2ntutc(ntfs_time_t t)
-{
- /* Convert to 100ns intervals and then add the NTFS time offset. */
- return (ntfs_time64_t)t * 10000000 + NTFS_TIME_OFFSET;
-}
-
-#undef NTFS_TIME_OFFSET
-
-/* Fill index name. */
-void ntfs_indexname(char *buf, int type)
-{
- char hex[] = "0123456789ABCDEF";
- int index;
- *buf++ = '$';
- *buf++ = 'I';
- for (index = 24; index > 0; index -= 4)
- if ((0xF << index) & type)
- break;
- while (index >= 0) {
- *buf++ = hex[(type >> index) & 0xF];
- index -= 4;
- }
- *buf = '\0';
-}
-
diff --git a/fs/ntfs/util.h b/fs/ntfs/util.h
deleted file mode 100644
index 5d21bb7fc9ac..000000000000
--- a/fs/ntfs/util.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * util.h - Header file for util.c
- *
- * Copyright (C) 1997 Régis Duchesne
- * Copyright (C) 2001 Anton Altaparmakov (AIA)
- */
-
-/* The first 16 inodes correspond to NTFS special files. */
-typedef enum {
- FILE_Mft = 0,
- FILE_MftMirr = 1,
- FILE_LogFile = 2,
- FILE_Volume = 3,
- FILE_AttrDef = 4,
- FILE_root = 5,
- FILE_BitMap = 6,
- FILE_Boot = 7,
- FILE_BadClus = 8,
- FILE_Secure = 9,
- FILE_UpCase = 10,
- FILE_Extend = 11,
- FILE_Reserved12 = 12,
- FILE_Reserved13 = 13,
- FILE_Reserved14 = 14,
- FILE_Reserved15 = 15,
-} NTFS_SYSTEM_FILES;
-
-/* Memory management */
-void *ntfs_calloc(int size);
-
-/* String operations */
-/* Copy Unicode <-> ASCII */
-void ntfs_ascii2uni(short int *to, char *from, int len);
-
-/* Comparison */
-int ntfs_uni_strncmp(short int* a, short int *b, int n);
-int ntfs_ua_strncmp(short int* a, char* b, int n);
-
-/* Same address space copies */
-void ntfs_put(ntfs_io *dest, void *src, ntfs_size_t n);
-void ntfs_get(void* dest, ntfs_io *src, ntfs_size_t n);
-
-/* Charset conversion */
-int ntfs_encodeuni(ntfs_volume *vol, ntfs_u16 *in, int in_len, char **out,
- int *out_len);
-int ntfs_decodeuni(ntfs_volume *vol, char *in, int in_len, ntfs_u16 **out,
- int *out_len);
-
-/* Time conversion */
-/* NT <-> Unix */
-ntfs_time_t ntfs_ntutc2unixutc(ntfs_time64_t ntutc);
-ntfs_time64_t ntfs_unixutc2ntutc(ntfs_time_t t);
-
-/* Attribute names */
-void ntfs_indexname(char *buf, int type);
-
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 414bf25bea5f..f59f0847d3fe 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -652,7 +652,6 @@ struct quota_mount_options
#include <linux/ext2_fs_sb.h>
#include <linux/ext3_fs_sb.h>
#include <linux/hpfs_fs_sb.h>
-#include <linux/ntfs_fs_sb.h>
#include <linux/msdos_fs_sb.h>
#include <linux/iso_fs_sb.h>
#include <linux/nfs_fs_sb.h>
@@ -710,7 +709,6 @@ struct super_block {
struct ext2_sb_info ext2_sb;
struct ext3_sb_info ext3_sb;
struct hpfs_sb_info hpfs_sb;
- struct ntfs_sb_info ntfs_sb;
struct msdos_sb_info msdos_sb;
struct isofs_sb_info isofs_sb;
struct nfs_sb_info nfs_sb;
diff --git a/include/linux/ntfs_fs.h b/include/linux/ntfs_fs.h
deleted file mode 100644
index 2bac6f57866f..000000000000
--- a/include/linux/ntfs_fs.h
+++ /dev/null
@@ -1,29 +0,0 @@
-#ifndef _LINUX_NTFS_FS_H
-#define _LINUX_NTFS_FS_H
-
-#include <asm/byteorder.h>
-
-#define NTFS_SECTOR_BITS 9
-#define NTFS_SECTOR_SIZE 512
-
-/*
- * Attribute flags (16-bit).
- */
-typedef enum {
- ATTR_IS_COMPRESSED = __constant_cpu_to_le16(0x0001),
- ATTR_COMPRESSION_MASK = __constant_cpu_to_le16(0x00ff),
- /* Compression method mask. Also,
- * first illegal value. */
- ATTR_IS_ENCRYPTED = __constant_cpu_to_le16(0x4000),
- ATTR_IS_SPARSE = __constant_cpu_to_le16(0x8000),
-} __attribute__ ((__packed__)) ATTR_FLAGS;
-
-/*
- * The two zones from which to allocate clusters.
- */
-typedef enum {
- MFT_ZONE,
- DATA_ZONE
-} NTFS_CLUSTER_ALLOCATION_ZONES;
-
-#endif
diff --git a/include/linux/ntfs_fs_i.h b/include/linux/ntfs_fs_i.h
deleted file mode 100644
index 45420c0420af..000000000000
--- a/include/linux/ntfs_fs_i.h
+++ /dev/null
@@ -1,97 +0,0 @@
-#ifndef _LINUX_NTFS_FS_I_H
-#define _LINUX_NTFS_FS_I_H
-
-#include <linux/types.h>
-
-/* Forward declarations, to keep number of mutual includes low */
-struct ntfs_attribute;
-struct ntfs_sb_info;
-
-/* Duplicate definitions from ntfs/ntfstypes.h */
-#ifndef NTFS_INTEGRAL_TYPES
-#define NTFS_INTEGRAL_TYPES
-typedef u8 ntfs_u8;
-typedef u16 ntfs_u16;
-typedef u32 ntfs_u32;
-typedef u64 ntfs_u64;
-typedef s8 ntfs_s8;
-typedef s16 ntfs_s16;
-typedef s32 ntfs_s32;
-typedef s64 ntfs_s64;
-#endif
-
-#ifndef NTMODE_T
-#define NTMODE_T
-typedef __kernel_mode_t ntmode_t;
-#endif
-#ifndef NTFS_UID_T
-#define NTFS_UID_T
-typedef uid_t ntfs_uid_t;
-#endif
-#ifndef NTFS_GID_T
-#define NTFS_GID_T
-typedef gid_t ntfs_gid_t;
-#endif
-#ifndef NTFS_SIZE_T
-#define NTFS_SIZE_T
-typedef __kernel_size_t ntfs_size_t;
-#endif
-#ifndef NTFS_TIME_T
-#define NTFS_TIME_T
-typedef __kernel_time_t ntfs_time_t;
-#endif
-
-/* unicode character type */
-#ifndef NTFS_WCHAR_T
-#define NTFS_WCHAR_T
-typedef u16 ntfs_wchar_t;
-#endif
-/* file offset */
-#ifndef NTFS_OFFSET_T
-#define NTFS_OFFSET_T
-typedef s64 ntfs_offset_t;
-#endif
-/* UTC */
-#ifndef NTFS_TIME64_T
-#define NTFS_TIME64_T
-typedef u64 ntfs_time64_t;
-#endif
-/*
- * This is really signed long long. So we support only volumes up to 2Tb. This
- * is ok as Win2k also only uses 32-bits to store clusters.
- * Whatever you do keep this a SIGNED value or a lot of NTFS users with
- * corrupted filesystems will lynch you! It causes massive fs corruption when
- * unsigned due to the nature of many checks relying on being performed on
- * signed quantities. (AIA)
- */
-#ifndef NTFS_CLUSTER_T
-#define NTFS_CLUSTER_T
-typedef s32 ntfs_cluster_t;
-#endif
-
-/* Definition of the NTFS in-memory inode structure. */
-struct ntfs_inode_info {
- struct ntfs_sb_info *vol;
- unsigned long i_number; /* Should be really 48 bits. */
- __u16 sequence_number; /* The current sequence number. */
- unsigned char *attr; /* Array of the attributes. */
- int attr_count; /* Size of attrs[]. */
- struct ntfs_attribute *attrs;
- int record_count; /* Size of records[]. */
- int *records; /* Array of the record numbers of the $Mft whose
- * attributes have been inserted in the inode. */
- union {
- struct {
- int recordsize;
- int clusters_per_record;
- } index;
- } u;
-};
-
-/* this is a kludge */
-struct ntfs_i {
- struct ntfs_inode_info n;
- struct inode vfs_inode;
-};
-
-#endif
diff --git a/include/linux/ntfs_fs_sb.h b/include/linux/ntfs_fs_sb.h
deleted file mode 100644
index f86cfe93cac6..000000000000
--- a/include/linux/ntfs_fs_sb.h
+++ /dev/null
@@ -1,61 +0,0 @@
-#ifndef _LINUX_NTFS_FS_SB_H
-#define _LINUX_NTFS_FS_SB_H
-
-#include <linux/ntfs_fs_i.h>
-
-struct ntfs_sb_info{
- /* Configuration provided by user at mount time. */
- ntfs_uid_t uid;
- ntfs_gid_t gid;
- ntmode_t umask;
- void *nls_map;
- unsigned int ngt;
- char mft_zone_multiplier;
- unsigned long mft_data_pos;
- ntfs_cluster_t mft_zone_pos;
- ntfs_cluster_t mft_zone_start;
- ntfs_cluster_t mft_zone_end;
- ntfs_cluster_t data1_zone_pos;
- ntfs_cluster_t data2_zone_pos;
- /* Configuration provided by user with the ntfstools.
- * FIXME: This is no longer possible. What is this good for? (AIA) */
- ntfs_size_t partition_bias; /* For access to underlying device. */
- /* Attribute definitions. */
- ntfs_u32 at_standard_information;
- ntfs_u32 at_attribute_list;
- ntfs_u32 at_file_name;
- ntfs_u32 at_volume_version;
- ntfs_u32 at_security_descriptor;
- ntfs_u32 at_volume_name;
- ntfs_u32 at_volume_information;
- ntfs_u32 at_data;
- ntfs_u32 at_index_root;
- ntfs_u32 at_index_allocation;
- ntfs_u32 at_bitmap;
- ntfs_u32 at_symlink; /* aka SYMBOLIC_LINK or REPARSE_POINT */
- /* Data read / calculated from the boot file. */
- int sector_size;
- int cluster_size;
- int cluster_size_bits;
- int mft_clusters_per_record;
- int mft_record_size;
- int mft_record_size_bits;
- int index_clusters_per_record;
- int index_record_size;
- int index_record_size_bits;
- ntfs_cluster_t nr_clusters;
- ntfs_cluster_t mft_lcn;
- ntfs_cluster_t mft_mirr_lcn;
- /* Data read from special files. */
- unsigned char *mft;
- unsigned short *upcase;
- unsigned int upcase_length;
- /* Inodes we always hold onto. */
- struct ntfs_inode_info *mft_ino;
- struct ntfs_inode_info *mftmirr;
- struct ntfs_inode_info *bitmap;
- struct super_block *sb;
- unsigned char ino_flags;
-};
-
-#endif