diff options
| author | Anton Altaparmakov <aia21@cam.ac.uk> | 2002-03-07 20:18:14 +0000 |
|---|---|---|
| committer | Anton Altaparmakov <aia21@cam.ac.uk> | 2002-03-07 20:18:14 +0000 |
| commit | 6c8b850912a3f7dfbf9ddb687beec6e8b4ff72cb (patch) | |
| tree | 268679110320576913e9f9fbb66c049bcd5b5067 | |
| parent | c39e9205e9c097cfa94117a2e452957d2ce03c9e (diff) | |
Remove all traces of the old ntfs driver.
| -rw-r--r-- | Documentation/filesystems/ntfs.txt | 254 | ||||
| -rw-r--r-- | fs/Config.help | 29 | ||||
| -rw-r--r-- | fs/Config.in | 2 | ||||
| -rw-r--r-- | fs/Makefile | 1 | ||||
| -rw-r--r-- | fs/ntfs/Makefile | 11 | ||||
| -rw-r--r-- | fs/ntfs/attr.c | 872 | ||||
| -rw-r--r-- | fs/ntfs/attr.h | 38 | ||||
| -rw-r--r-- | fs/ntfs/dir.c | 1104 | ||||
| -rw-r--r-- | fs/ntfs/dir.h | 48 | ||||
| -rw-r--r-- | fs/ntfs/fs.c | 1233 | ||||
| -rw-r--r-- | fs/ntfs/inode.c | 2317 | ||||
| -rw-r--r-- | fs/ntfs/inode.h | 58 | ||||
| -rw-r--r-- | fs/ntfs/macros.h | 40 | ||||
| -rw-r--r-- | fs/ntfs/ntfsendian.h | 60 | ||||
| -rw-r--r-- | fs/ntfs/ntfstypes.h | 84 | ||||
| -rw-r--r-- | fs/ntfs/struct.h | 69 | ||||
| -rw-r--r-- | fs/ntfs/super.c | 1413 | ||||
| -rw-r--r-- | fs/ntfs/super.h | 32 | ||||
| -rw-r--r-- | fs/ntfs/support.c | 316 | ||||
| -rw-r--r-- | fs/ntfs/support.h | 59 | ||||
| -rw-r--r-- | fs/ntfs/sysctl.c | 55 | ||||
| -rw-r--r-- | fs/ntfs/sysctl.h | 17 | ||||
| -rw-r--r-- | fs/ntfs/unistr.c | 168 | ||||
| -rw-r--r-- | fs/ntfs/unistr.h | 44 | ||||
| -rw-r--r-- | fs/ntfs/util.c | 265 | ||||
| -rw-r--r-- | fs/ntfs/util.h | 56 | ||||
| -rw-r--r-- | include/linux/fs.h | 2 | ||||
| -rw-r--r-- | include/linux/ntfs_fs.h | 29 | ||||
| -rw-r--r-- | include/linux/ntfs_fs_i.h | 97 | ||||
| -rw-r--r-- | include/linux/ntfs_fs_sb.h | 61 |
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 = ¶m; - 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 |
